# Test the low-level rbyd data-structure after = 'test_bd' # test with a number of different erase values defines.ERASE_VALUE = [0xff, 0x00, -1] # 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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_ATTR(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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT; ''' [cases.test_rbyd_lookup] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT; ''' [cases.test_rbyd_atomic_get] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0; lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(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_ATTR(2), &data) => LFS_ERR_NOENT; lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0; lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(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_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0; lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), &data) => 0; lfsr_data_read(&lfs, &data, buffer, 4) => 4; lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &data) => 0; lfsr_data_read(&lfs, &data, buffer, 4) => 4; lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &data) => LFS_ERR_NOENT; lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0; lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), &data) => 0; lfsr_data_read(&lfs, &data, buffer, 4) => 4; lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &data) => 0; lfsr_data_read(&lfs, &data, buffer, 4) => 4; lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0; lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), &data) => 0; lfsr_data_read(&lfs, &data, buffer, 4) => 4; lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &data) => 0; lfsr_data_read(&lfs, &data, buffer, 4) => 4; lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &data) => LFS_ERR_NOENT; lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0; lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), &data) => 0; lfsr_data_read(&lfs, &data, buffer, 4) => 4; lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &data) => 0; lfsr_data_read(&lfs, &data, buffer, 4) => 4; lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &data) => LFS_ERR_NOENT; ''' [cases.test_rbyd_get] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0; lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(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_ATTR(2), &data) => LFS_ERR_NOENT; lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0; lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(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_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0; lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), &data) => 0; lfsr_data_read(&lfs, &data, buffer, 4) => 4; lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &data) => 0; lfsr_data_read(&lfs, &data, buffer, 4) => 4; lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &data) => LFS_ERR_NOENT; lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0; lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), &data) => 0; lfsr_data_read(&lfs, &data, buffer, 4) => 4; lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &data) => 0; lfsr_data_read(&lfs, &data, buffer, 4) => 4; lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0; lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), &data) => 0; lfsr_data_read(&lfs, &data, buffer, 4) => 4; lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &data) => 0; lfsr_data_read(&lfs, &data, buffer, 4) => 4; lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &data) => LFS_ERR_NOENT; lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0; lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), &data) => 0; lfsr_data_read(&lfs, &data, buffer, 4) => 4; lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &data) => 0; lfsr_data_read(&lfs, &data, buffer, 4) => 4; lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &data) => LFS_ERR_NOENT; ''' [cases.test_rbyd_bifoliate] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, LFS_M_RDWR, 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 // .-'| // 1 1 2 rbyd = init_rbyd; lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); ''' [cases.test_rbyd_bflips] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, LFS_M_RDWR, 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 // .----'| // 1 2 1 2 2 rbyd = init_rbyd; lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); // flip a black edge // b // .-'| => .-'| // 1 2 1 2 1 rbyd = init_rbyd; lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); ''' [cases.test_rbyd_trifoliate] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, LFS_M_RDWR, 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 // | 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(3)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); // flip a black edge // >r // .-'| // | >b // .-'| .--|-'| // 2 3 2 3 1 rbyd = init_rbyd; lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(3)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); ''' [cases.test_rbyd_rflips] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, LFS_M_RDWR, 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 // | 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(3)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); // ignore a red edge, flip a black edge // | >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_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(3)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); // flip a red edge and black edge // r // .----'| .-'| // | | >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_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(3)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); // flip a red edge, ignore a black edge // 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(3)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); ''' [cases.test_rbyd_quadrifoliate] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, LFS_M_RDWR, 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 // | .----'| // | 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(3)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); // ignore a red edge, flip a black edge // y // .-------'| .-'| // r | >r // .----'| => | .-'| => .--|-'| // | b | | 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(3)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); // flip a red edge and black edge // >y // .-'| // 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(3)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); // flip a red edge, ignore a black edge // >y // .-------'| // r // .-'| => | .-'| // | >b | | 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(3)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); ''' [cases.test_rbyd_rotations] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, LFS_M_RDWR, 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 // | .----'| // | 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(3)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); // yellow and red alt the same // | .----'| // | 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(3)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); // yellow and black alt the same // r | | .----'| => | .-'| // | >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_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(3)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); // red and black alt the same // >y r | | .----'| => | .-'| // | 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(3)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); ''' [cases.test_rbyd_ysplits] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, LFS_M_RDWR, 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 // | 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(3)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); // split a yellow triple, taking the black alt // | 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(3)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); // split a yellow triple, taking the red alt // b // .-------'| .-'| // | .--------|-'| // | | 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(3)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); // split a yellow triple, taking the yellow alt // b // .-------'| .-'| // | b // | .----'| => .-----|-'| // | | 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(3)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); ''' [cases.test_rbyd_quintifoliate] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, LFS_M_RDWR, 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 // | .----' | // | 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(3)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(5)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); // split a yellow triple, taking the black alt // | .----' | // | r // | .----'| | | .-'| // | | 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)), LFSR_RAT( LFSR_TAG_ATTR(5), 0, LFSR_DATA_BUF("\xee\xee\xee\xee", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(3)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(5)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); // split a yellow triple, taking the red alt // >b // .-'| // b // | .----'| => | .-----|-'| // | | 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)), LFSR_RAT( LFSR_TAG_ATTR(5), 0, LFSR_DATA_BUF("\xee\xee\xee\xee", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(3)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(5)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); // split a yellow triple, taking the yellow alt // >b // .-'| // r // .-------'| .-----|-'| // | b // | .----'| => .--|-----|-'| // | | 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)), LFSR_RAT( LFSR_TAG_ATTR(5), 0, LFSR_DATA_BUF("\xee\xee\xee\xee", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(3)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(5)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); ''' [cases.test_rbyd_prunes] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, LFS_M_RDWR, 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 // | .----' | // | | 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)), LFSR_RAT( LFSR_TAG_ATTR(5), 0, LFSR_DATA_BUF("\xee\xee\xee\xee", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(3)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(5)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); // prune by taking a red alt // b // .-------'| | .-'| // | .-----------|-'| // | | 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)), LFSR_RAT( LFSR_TAG_ATTR(5), 0, LFSR_DATA_BUF("\xee\xee\xee\xee", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(3)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(5)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); // prune by taking a yellow alt (this needs to prune during the rflip) // b // .-------'| | .-'| // | b // | .----' | => .--------|-'| // | | 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)), LFSR_RAT( LFSR_TAG_ATTR(5), 0, LFSR_DATA_BUF("\xee\xee\xee\xee", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(3)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(5)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); ''' [cases.test_rbyd_sextifoliate] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, LFS_M_RDWR, 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 // | | .-------'| // | | 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)), LFSR_RAT( LFSR_TAG_ATTR(5), 0, LFSR_DATA_BUF("\xee\xee\xee\xee", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(3)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(5)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(6), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(6)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); // prune by taking a red alt // b // .-'| .-'| // b // | .----' | => | .--------|-'| // | | 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)), LFSR_RAT( LFSR_TAG_ATTR(5), 0, LFSR_DATA_BUF("\xee\xee\xee\xee", 4)), LFSR_RAT( LFSR_TAG_ATTR(6), 0, LFSR_DATA_BUF("\xff\xff\xff\xff", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(3)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(5)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(6), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(6)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); // prune by taking a yellow alt (this needs to prune during the rflip) // b // .-'| .-'| // r // .-------'| | .--------|-'| // | b // | .----' | => .--|--------|-'| // | | 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)), LFSR_RAT( LFSR_TAG_ATTR(5), 0, LFSR_DATA_BUF("\xee\xee\xee\xee", 4)), LFSR_RAT( LFSR_TAG_ATTR(6), 0, LFSR_DATA_BUF("\xff\xff\xff\xff", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(3)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(5)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(6), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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, LFS_M_RDWR, 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_rat rats[N]; for (unsigned j = 0; j < N; j++) { rats[j] = LFSR_RAT( LFSR_TAG_ATTR(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, rats, 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_ATTR(j+1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(j+1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); } // keep track of the worst size if (lfsr_rbyd_eoff(&rbyd) > worst_size) { worst_size = lfsr_rbyd_eoff(&rbyd); 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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(j+1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(j+1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); } // keep track of the worst size if (lfsr_rbyd_eoff(&rbyd) > worst_size) { worst_size = lfsr_rbyd_eoff(&rbyd); 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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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, LFS_M_RDWR, 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_rat rats[N]; for (unsigned j = 0; j < N; j++) { rats[j] = LFSR_RAT( LFSR_TAG_ATTR(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, rats, 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_ATTR(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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(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(lfsr_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfsr_rbyd_eoff(&rbyd)) => 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, lfsr_rbyd_eoff(&rbyd), NULL, false) => 0; lfsr_bd_flush(&lfs, NULL, false) => 0; // update each tag in permutation order for (unsigned j = 0; j < N; j++) { lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(j+1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(j+1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 6); } // keep track of the worst size if (lfsr_rbyd_eoff(&rbyd) > worst_size) { worst_size = lfsr_rbyd_eoff(&rbyd); 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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(x & 0x7f), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_ATTR(1), 0, LFSR_DATA_NULL()))) => 0; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), &rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_ATTR(1), 0, LFSR_DATA_NULL()))) => 0; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_ATTR(2), 0, LFSR_DATA_NULL()))) => 0; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(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(lfsr_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfsr_rbyd_eoff(&rbyd)) => 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, lfsr_rbyd_eoff(&rbyd), NULL, false) => 0; lfsr_bd_flush(&lfs, NULL, false) => 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_ATTR(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_ATTR(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 == 0); assert(tag_ == LFSR_TAG_ATTR(j+1+1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); } } else { assert(tag_ == LFSR_TAG_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(k+1), &rid_, &tag_, NULL, &data_) => 0; if (k == j) { assert(tag_ == LFSR_TAG_ATTR(k+1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 6); } else { assert(tag_ == LFSR_TAG_ATTR(k+1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); } } // keep track of the worst size if (lfsr_rbyd_eoff(&rbyd) > worst_size) { worst_size = lfsr_rbyd_eoff(&rbyd); 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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(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(lfsr_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfsr_rbyd_eoff(&rbyd)) => 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, lfsr_rbyd_eoff(&rbyd), NULL, false) => 0; lfsr_bd_flush(&lfs, NULL, false) => 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_ATTR(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_ATTR(k+1+1)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); } else { assert(tag_ == LFSR_TAG_ATTR(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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)))) => 0; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_ATTR(1), 0, LFSR_DATA_NULL()))) => 0; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5), &rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_ATTR(3), 0, LFSR_DATA_NULL()))) => 0; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5), &rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_ATTR(5), 0, LFSR_DATA_NULL()))) => 0; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5), &rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT; ''' [cases.test_rbyd_remove_again] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)), LFSR_RAT( LFSR_TAG_ATTR(5), 0, LFSR_DATA_BUF("\xee\xee\xee\xee", 4)))) => 0; // remove several attributes lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_ATTR(1), 0, LFSR_DATA_NULL()), LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_ATTR(3), 0, LFSR_DATA_NULL()), LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_ATTR(5), 0, LFSR_DATA_NULL()))) => 0; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_ATTR(1), 0, LFSR_DATA_NULL()))) => 0; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5), &rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_ATTR(3), 0, LFSR_DATA_NULL()))) => 0; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5), &rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_ATTR(5), 0, LFSR_DATA_NULL()))) => 0; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_ATTR(1), 0, LFSR_DATA_NULL()))) => 0; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5), &rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_ATTR(3), 0, LFSR_DATA_NULL()))) => 0; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5), &rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_ATTR(5), 0, LFSR_DATA_NULL()))) => 0; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(2)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(4)); assert(rid_ == -1); assert(lfsr_data_size(data_) == 4); lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5), &rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT; ''' [cases.test_rbyd_remove_all] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_ATTR(1), 0, LFSR_DATA_NULL()))) => 0; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), &rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_ATTR(1), 0, LFSR_DATA_NULL()), LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_ATTR(2), 0, LFSR_DATA_NULL()))) => 0; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), &rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_ATTR(2), 0, LFSR_DATA_NULL()), LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_ATTR(1), 0, LFSR_DATA_NULL()))) => 0; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), &rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(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(lfsr_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfsr_rbyd_eoff(&rbyd)) => 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, lfsr_rbyd_eoff(&rbyd), NULL, false) => 0; lfsr_bd_flush(&lfs, NULL, false) => 0; // remove each tag in permutation order for (unsigned j = 0; j < N; j++) { lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_ATTR(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_ATTR(j+1), &rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT; } // try resuming from all tags being removed lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(j+1), &rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT; } // keep track of the worst size if (lfsr_rbyd_eoff(&rbyd) > worst_size) { worst_size = lfsr_rbyd_eoff(&rbyd); 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)' fuzz = 'SEED' # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, LFS_M_RDWR, 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 rat uint8_t rat = TEST_PRNG(&prng) % N; // choose append or remove if (TEST_PRNG(&prng) & 1) { printf("a0x%02x=%c", rat, 'a'+(i % 26)); } else { printf("r0x%02x", rat); } 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 rat uint8_t rat = TEST_PRNG(&prng) % N; // choose append or remove if (TEST_PRNG(&prng) & 1) { // update our sim sim[rat] = 'a'+(i % 26); // update our rbyd lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(rat), 0, LFSR_DATA_BUF(&(uint8_t){'a'+(i % 26)}, 1)))) => 0; } else { // update our sim sim[rat] = '\0'; // update our rbyd lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_ATTR(rat), 0, LFSR_DATA_NULL()))) => 0; } } // compare rbyd vs simulation printf("expd: ["); bool first = true; for (unsigned rat = 0; rat < N; rat++) { if (sim[rat]) { if (!first) { printf(", "); } first = false; printf("0x%02x=%c", rat, sim[rat]); } } printf("]\n"); printf("rbyd: ["); first = true; for (unsigned rat = 0; rat < N; rat++) { int err = lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(rat), &data); if (!err) { lfs_ssize_t size = lfsr_data_read(&lfs, &data, buffer, 4); if (!first) { printf(", "); } first = false; printf("0x%02x=%.*s", rat, size, buffer); } } printf("]\n"); for (unsigned rat = 0; rat < N; rat++) { int err = lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(rat), &data); if (sim[rat]) { assert(err == 0); lfs_ssize_t size = lfsr_data_read(&lfs, &data, buffer, 4); assert(size == 1); assert(memcmp(&sim[rat], 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, LFS_M_RDWR, 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_RATS( LFSR_RAT( 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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( 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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( 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, LFS_M_RDWR, 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_RATS( LFSR_RAT( 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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT( 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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT( 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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_RATS( LFSR_RAT( 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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT( 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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT( 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, LFS_M_RDWR, 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_RATS( LFSR_RAT( 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 (lfsr_rbyd_eoff(&rbyd) > worst_size) { worst_size = lfsr_rbyd_eoff(&rbyd); 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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( 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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT( 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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT( 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, LFS_M_RDWR, 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_RATS( LFSR_RAT( 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, LFS_M_RDWR, 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_RATS( LFSR_RAT(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 rat testing ### [cases.test_rbyd_atomic_mixed] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(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_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xbb\xbb", 2)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(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_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xbb\xbb", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xbb\xbb", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xbb\xbb", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xcc\xcc", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xcc\xcc", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF(names[perm[j] % 6], 4)))) => 0; // note urats have a smaller size to help debugging for (unsigned u = 0; u < M; u++) { lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(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 (lfsr_rbyd_eoff(&rbyd) > worst_size) { worst_size = lfsr_rbyd_eoff(&rbyd); 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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xbb\xbb", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF(names[perm[j] % 6], 4)))) => 0; // note urats have a smaller size to help debugging for (unsigned u = 0; u < M; u++) { lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF(names[j % 6], 4)))) => 0; // note urats have a smaller size to help debugging for (unsigned u = 0; u < M; u++) { lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(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(lfsr_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfsr_rbyd_eoff(&rbyd)) => 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, lfsr_rbyd_eoff(&rbyd), NULL, false) => 0; lfsr_bd_flush(&lfs, NULL, false) => 0; // update each tag in permutation order for (unsigned j = 0; j < N*M; j++) { lfsr_rbyd_commit(&lfs, &rbyd, perm[j]/M, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(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 (lfsr_rbyd_eoff(&rbyd) > worst_size) { worst_size = lfsr_rbyd_eoff(&rbyd); 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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF(names[perm[j] % 6], 4)))) => 0; // note urats have a smaller size to help debugging for (unsigned u = 0; u < M; u++) { lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(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(lfsr_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfsr_rbyd_eoff(&rbyd)) => 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, lfsr_rbyd_eoff(&rbyd), NULL, false) => 0; lfsr_bd_flush(&lfs, NULL, false) => 0; lfsr_rbyd_commit(&lfs, &rbyd, j/M, LFSR_RATS( LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_ATTR((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_ATTR(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 == 0); assert(tag_ == LFSR_TAG_REG); assert(rid_ == k+1); assert(lfsr_data_size(data_) == 4); } else { assert(err == 0); assert(tag_ == LFSR_TAG_ATTR(u+1+1)); assert(rid_ == k); assert(lfsr_data_size(data_) == 2); } } else { assert(tag_ == LFSR_TAG_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_ATTR((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_ATTR(u+1), &rid_, &tag_, NULL, &data_) => 0; if (k == j/M && u == j%M) { assert(tag_ == LFSR_TAG_ATTR(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_ATTR(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 (lfsr_rbyd_eoff(&rbyd) > worst_size) { worst_size = lfsr_rbyd_eoff(&rbyd); 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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF(names[j % 6], 4)))) => 0; // note urats have a smaller size to help debugging for (unsigned u = 0; u < M; u++) { lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(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(lfsr_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfsr_rbyd_eoff(&rbyd)) => 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, lfsr_rbyd_eoff(&rbyd), NULL, false) => 0; lfsr_bd_flush(&lfs, NULL, false) => 0; // remove each tag in permutation order for (unsigned j = 0; j < N*M; j++) { lfsr_rbyd_commit(&lfs, &rbyd, perm[j]/M, LFSR_RATS( LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_ATTR(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_ATTR(u+1), &data) => LFS_ERR_NOENT; } } // keep track of the worst size if (lfsr_rbyd_eoff(&rbyd) > worst_size) { worst_size = lfsr_rbyd_eoff(&rbyd); 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, LFS_M_RDWR, 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 ratibutes, if this fails // it should fail atomically struct lfsr_rat rats[1+M]; rats[0] = LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF(names[x % 6], 4)); for (unsigned u = 0; u < M; u++) { rats[1+u] = LFSR_RAT( LFSR_TAG_ATTR(u+1), 0, LFSR_DATA_BUF(names[x % 6], 2)); } int err = lfsr_rbyd_commit(&lfs, &rbyd, x, rats, 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_ATTR(u+1), &rid_, &tag_, NULL, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(perm[j]+1), 0, LFSR_DATA_BUF(names[perm[j] % 6], 1)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATS( LFSR_RAT( 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_ATTR(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_ATTR(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 (lfsr_rbyd_eoff(&rbyd) > worst_size) { worst_size = lfsr_rbyd_eoff(&rbyd); 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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(perm[j]+1), 0, LFSR_DATA_BUF(names[perm[j] % 6], 1)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATS( LFSR_RAT( 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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 (lfsr_rbyd_eoff(&rbyd) > worst_size) { worst_size = lfsr_rbyd_eoff(&rbyd); 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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT(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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT(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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_RATS( LFSR_RAT(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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT(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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT(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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xbb\xbb", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xbb\xbb", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xbb\xbb", 2)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xcc\xcc", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_RATS( LFSR_RAT(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xbb\xbb", 2)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xcc\xcc", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xbb\xbb", 2)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xcc\xcc", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(5), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(6), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xcc\xcc", 2)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xee\xee\xee\xee", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(5), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(6), 0, LFSR_DATA_BUF("\xee\xee", 2)), // propagate yellow to the root LFSR_RAT( LFSR_TAG_ATTR(6), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(6), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(6), 0, LFSR_DATA_BUF("\xee\xee", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(1), &data) => LFS_ERR_NOENT; // try to recreate lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT( 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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(1), &data) => LFS_ERR_NOENT; ''' [cases.test_rbyd_delete_range_r] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xcc\xcc", 2)), LFSR_RAT( LFSR_TAG_ATTR(3), +1, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(5), 0, LFSR_DATA_BUF("\xee\xee", 2)), // propagate yellow to the root LFSR_RAT( LFSR_TAG_ATTR(5), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(5), 0, LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_REG, 0, LFSR_DATA_BUF("\xee\xee\xee\xee", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(1), &data) => LFS_ERR_NOENT; // try to recreate lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT( 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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(1), &data) => LFS_ERR_NOENT; ''' [cases.test_rbyd_delete_range_y] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xcc\xcc", 2)), LFSR_RAT( LFSR_TAG_ATTR(4), +1, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(5), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(6), 0, LFSR_DATA_BUF("\xee\xee", 2)), // propagate yellow to the root LFSR_RAT( LFSR_TAG_ATTR(6), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_ATTR(5), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(6), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(7), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(8), 0, LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), // propagate yellow LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_REG, 0, LFSR_DATA_BUF("\xee\xee\xee\xee", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(8), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(7), 0, LFSR_DATA_BUF("\xee\xee", 2)), // propagate yellow LFSR_RAT( LFSR_TAG_ATTR(7), 0, LFSR_DATA_BUF("\xee\xee", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(1), &data) => LFS_ERR_NOENT; // try to recreate lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT( 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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(1), &data) => LFS_ERR_NOENT; ''' [cases.test_rbyd_delete_range_rydy] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(4), +1, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(5), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(6), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(7), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(8), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(9), 0, LFSR_DATA_BUF("\xee\xee", 2)), // propagate yellow to the root LFSR_RAT( LFSR_TAG_ATTR(9), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_ATTR(5), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(6), 0, LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_REG, 0, LFSR_DATA_BUF("\xee\xee\xee\xee", 4)), // propagate yellow LFSR_RAT( LFSR_TAG_REG, 0, LFSR_DATA_BUF("\xee\xee\xee\xee", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(1), &data) => LFS_ERR_NOENT; // try to recreate lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT( 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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(1), &data) => LFS_ERR_NOENT; ''' [cases.test_rbyd_delete_range_rydy_backwards] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(9), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(2), +1, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(5), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(6), 0, LFSR_DATA_BUF("\xee\xee", 2)), // propagate yellow to the root LFSR_RAT( LFSR_TAG_ATTR(6), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_REG, 0, LFSR_DATA_BUF("\xee\xee\xee\xee", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(5), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(6), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(7), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(8), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), // propagate yellow LFSR_RAT( LFSR_TAG_ATTR(8), 0, LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(1), &data) => LFS_ERR_NOENT; // try to recreate lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT( 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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(1), &data) => LFS_ERR_NOENT; ''' [cases.test_rbyd_delete_range_rydye] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(2), +1, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(5), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(6), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(7), 0, LFSR_DATA_BUF("\xee\xee", 2)), // propagate yellow to the root LFSR_RAT( LFSR_TAG_ATTR(7), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_ATTR(5), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(6), 0, LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_REG, 0, LFSR_DATA_BUF("\xee\xee\xee\xee", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xcc\xcc", 2)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xcc\xcc", 2)), // propagate yellow LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xcc\xcc", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(1), &data) => LFS_ERR_NOENT; // try to recreate lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT( 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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(1), &data) => LFS_ERR_NOENT; ''' [cases.test_rbyd_delete_range_rydye_backwards] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(1), +1, LFSR_DATA_BUF("\xcc\xcc", 2)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xcc\xcc", 2)), LFSR_RAT( LFSR_TAG_ATTR(2), +1, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(5), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(6), 0, LFSR_DATA_BUF("\xee\xee", 2)), // propagate yellow to the root LFSR_RAT( LFSR_TAG_ATTR(6), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_REG, 0, LFSR_DATA_BUF("\xee\xee\xee\xee", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(5), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(6), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(7), 0, LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT( LFSR_TAG_REG, 0, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), // propagate yellow LFSR_RAT( LFSR_TAG_REG, 0, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(1), &data) => LFS_ERR_NOENT; // try to recreate lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT( 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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(1), &data) => LFS_ERR_NOENT; ''' [cases.test_rbyd_delete_range_dryy] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(5), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(6), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(2), +1, LFSR_DATA_BUF("\xcc\xcc", 2)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xcc\xcc", 2)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xee\xee\xee\xee", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(5), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(6), 0, LFSR_DATA_BUF("\xee\xee", 2)), // propagate yellow to the root LFSR_RAT( LFSR_TAG_ATTR(6), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(6), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_ATTR(7), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(8), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(11), 0, LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xcc\xcc", 2)), // propagate yellow LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xcc\xcc", 2)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xcc\xcc", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(12), 0, LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT( LFSR_TAG_REG, 0, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), // propagate yellow LFSR_RAT( LFSR_TAG_REG, 0, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(13), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(14), 0, LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(9), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(10), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), // propagate yellow LFSR_RAT( LFSR_TAG_ATTR(10), 0, LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(1), &data) => LFS_ERR_NOENT; // try to recreate lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT( 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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(1), &data) => LFS_ERR_NOENT; ''' [cases.test_rbyd_delete_range_dryy_backwards] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(5), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(6), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xcc\xcc", 2)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xcc\xcc", 2)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xcc\xcc", 2)), LFSR_RAT( LFSR_TAG_ATTR(6), +1, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(7), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(8), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(9), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(10), 0, LFSR_DATA_BUF("\xee\xee", 2)), // propagate yellow to the root LFSR_RAT( LFSR_TAG_ATTR(10), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(10), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_ATTR(11), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(12), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(13), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(14), 0, LFSR_DATA_BUF("\xee\xee", 2)), // propagate yellow LFSR_RAT( LFSR_TAG_ATTR(14), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(14), 0, LFSR_DATA_BUF("\xee\xee", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xee\xee", 2)), // propagate yellow LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("\xee\xee", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_REG, 0, LFSR_DATA_BUF("\xee\xee\xee\xee", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(5), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xee\xee", 2)), // propagate yellow LFSR_RAT( LFSR_TAG_ATTR(4), 0, LFSR_DATA_BUF("\xee\xee", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(1), &data) => LFS_ERR_NOENT; // try to recreate lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT( 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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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, LFS_M_RDWR, 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_RATS( LFSR_RAT( 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(lfsr_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfsr_rbyd_eoff(&rbyd)) => 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, lfsr_rbyd_eoff(&rbyd), NULL, false) => 0; lfsr_bd_flush(&lfs, NULL, false) => 0; lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATS( LFSR_RAT(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_RATS( LFSR_RAT( 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 (lfsr_rbyd_eoff(&rbyd) > worst_size) { worst_size = lfsr_rbyd_eoff(&rbyd); 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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF(names[perm[j] % 6], 4)))) => 0; // note urats have a smaller size to help debugging for (unsigned u = 0; u < M; u++) { lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(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(lfsr_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfsr_rbyd_eoff(&rbyd)) => 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, lfsr_rbyd_eoff(&rbyd), NULL, false) => 0; lfsr_bd_flush(&lfs, NULL, false) => 0; lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATS( LFSR_RAT(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_ATTR(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_ATTR(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_RATS( LFSR_RAT( 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(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_ATTR(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 (lfsr_rbyd_eoff(&rbyd) > worst_size) { worst_size = lfsr_rbyd_eoff(&rbyd); 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, LFS_M_RDWR, 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_RATS( LFSR_RAT( 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(lfsr_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfsr_rbyd_eoff(&rbyd)) => 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, lfsr_rbyd_eoff(&rbyd), NULL, false) => 0; lfsr_bd_flush(&lfs, NULL, false) => 0; lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATS( LFSR_RAT(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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF(names[perm[j] % 6], 4)))) => 0; // note urats have a smaller size to help debugging for (unsigned u = 0; u < M; u++) { lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(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(lfsr_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfsr_rbyd_eoff(&rbyd)) => 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, lfsr_rbyd_eoff(&rbyd), NULL, false) => 0; lfsr_bd_flush(&lfs, NULL, false) => 0; lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATS( LFSR_RAT(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_ATTR(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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT(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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT(LFSR_TAG_RM, -1, LFSR_DATA_NULL()), LFSR_RAT(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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT(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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_RATS( LFSR_RAT(LFSR_TAG_RM, -1, LFSR_DATA_NULL()), LFSR_RAT(LFSR_TAG_RM, -1, LFSR_DATA_NULL()), LFSR_RAT(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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT(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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT(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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xbb\xbb", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATS( LFSR_RAT(LFSR_TAG_RM, -1, LFSR_DATA_NULL()), LFSR_RAT(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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xbb\xbb", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT(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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xbb\xbb", 2)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xcc\xcc", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_RATS( LFSR_RAT(LFSR_TAG_RM, -1, LFSR_DATA_NULL()), LFSR_RAT(LFSR_TAG_RM, -1, LFSR_DATA_NULL()), LFSR_RAT(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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xbb\xbb", 2)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xcc\xcc", 2)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT(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, LFS_M_RDWR, 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_RATS( LFSR_RAT( 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(lfsr_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfsr_rbyd_eoff(&rbyd)) => 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, lfsr_rbyd_eoff(&rbyd), NULL, false) => 0; lfsr_bd_flush(&lfs, NULL, false) => 0; // delete each rid in permutation order for (unsigned j = 0; j < N; j++) { // adjust rid based on previous deletions uint16_t rid = perm[j]; for (unsigned k = 0; k < j; k++) { if (perm[k] < perm[j]) { rid -= 1; } } lfs_size_t rbyd_weight_before = rbyd.weight; lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATS( LFSR_RAT(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_RATS( LFSR_RAT( 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 (lfsr_rbyd_eoff(&rbyd) > worst_size) { worst_size = lfsr_rbyd_eoff(&rbyd); 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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF(names[j % 6], 4)))) => 0; // note urats have a smaller size to help debugging for (unsigned u = 0; u < M; u++) { lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(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(lfsr_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfsr_rbyd_eoff(&rbyd)) => 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, lfsr_rbyd_eoff(&rbyd), NULL, false) => 0; lfsr_bd_flush(&lfs, NULL, false) => 0; // delete each rid in permutation order for (unsigned j = 0; j < N; j++) { // adjust rid based on previous deletions uint16_t rid = perm[j]; for (unsigned k = 0; k < j; k++) { if (perm[k] < perm[j]) { rid -= 1; } } lfs_size_t rbyd_weight_before = rbyd.weight; lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATS( LFSR_RAT(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_RATS( LFSR_RAT( 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(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_ATTR(1), &data) => LFS_ERR_NOENT; // keep track of the worst size if (lfsr_rbyd_eoff(&rbyd) > worst_size) { worst_size = lfsr_rbyd_eoff(&rbyd); 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)' fuzz = 'SEED' # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, LFS_M_RDWR, 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_RATS( LFSR_RAT( 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_RATS( LFSR_RAT(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, LFS_M_RDWR, 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_RATS( LFSR_RAT( 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_RATS( LFSR_RAT( 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_RATS( LFSR_RAT( 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_RATS( LFSR_RAT( 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_RATS( LFSR_RAT( 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, LFS_M_RDWR, 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_RATS( // make id0 with weight w1 LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), // make id2 with weight w2 LFSR_RAT( LFSR_TAG_REG, +2, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), // make id5 with weight w3 LFSR_RAT( LFSR_TAG_REG, +3, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), // make id9 with weight w4 LFSR_RAT( LFSR_TAG_REG, +4, LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)), // make id14 with weight w5 LFSR_RAT( 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, LFS_M_RDWR, 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_RATS( LFSR_RAT( 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, LFS_M_RDWR, 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_RATS( LFSR_RAT( 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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("unrelated", 9)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == 0); assert(weight_ == 0); assert(lfsr_data_size(data_) == 2); lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(3), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == 0); assert(weight_ == 0); assert(lfsr_data_size(data_) == 2); lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xbb\xbb", 2)), LFSR_RAT( LFSR_TAG_GROW, +1, LFSR_DATA_NULL()), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb", 2)))) => 0; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == 0); assert(weight_ == 0); assert(lfsr_data_size(data_) == 2); lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == 2); assert(weight_ == 0); assert(lfsr_data_size(data_) == 2); lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(3), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == 0); assert(weight_ == 0); assert(lfsr_data_size(data_) == 2); lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == 2); assert(weight_ == 0); assert(lfsr_data_size(data_) == 2); lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xcc\xcc", 2)), LFSR_RAT( LFSR_TAG_GROW, +2, LFSR_DATA_NULL()), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xcc\xcc", 2)))) => 0; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == 0); assert(weight_ == 0); assert(lfsr_data_size(data_) == 2); lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == 2); assert(weight_ == 0); assert(lfsr_data_size(data_) == 2); lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == 5); assert(weight_ == 0); assert(lfsr_data_size(data_) == 2); lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(3), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == 0); assert(weight_ == 0); assert(lfsr_data_size(data_) == 2); lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == 2); assert(weight_ == 0); assert(lfsr_data_size(data_) == 2); lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == 5); assert(weight_ == 0); assert(lfsr_data_size(data_) == 2); lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xdd\xdd", 2)), LFSR_RAT( LFSR_TAG_GROW, +3, LFSR_DATA_NULL()), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xdd\xdd", 2)))) => 0; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == 0); assert(weight_ == 0); assert(lfsr_data_size(data_) == 2); lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == 2); assert(weight_ == 0); assert(lfsr_data_size(data_) == 2); lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == 5); assert(weight_ == 0); assert(lfsr_data_size(data_) == 2); lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == 9); assert(weight_ == 0); assert(lfsr_data_size(data_) == 2); lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(3), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == 0); assert(weight_ == 0); assert(lfsr_data_size(data_) == 2); lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == 2); assert(weight_ == 0); assert(lfsr_data_size(data_) == 2); lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == 5); assert(weight_ == 0); assert(lfsr_data_size(data_) == 2); lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == 9); assert(weight_ == 0); assert(lfsr_data_size(data_) == 2); lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xee\xee\xee\xee", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_GROW, +4, LFSR_DATA_NULL()), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xee\xee", 2)))) => 0; lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == 0); assert(weight_ == 0); assert(lfsr_data_size(data_) == 2); lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == 2); assert(weight_ == 0); assert(lfsr_data_size(data_) == 2); lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == 5); assert(weight_ == 0); assert(lfsr_data_size(data_) == 2); lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == 9); assert(weight_ == 0); assert(lfsr_data_size(data_) == 2); lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == 14); assert(weight_ == 0); assert(lfsr_data_size(data_) == 2); lfsr_rbyd_lookupnext(&lfs, &rbyd, 14, LFSR_TAG_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(3), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == 0); assert(weight_ == 0); assert(lfsr_data_size(data_) == 2); lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == 2); assert(weight_ == 0); assert(lfsr_data_size(data_) == 2); lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == 5); assert(weight_ == 0); assert(lfsr_data_size(data_) == 2); lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == 9); assert(weight_ == 0); assert(lfsr_data_size(data_) == 2); lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == 14); assert(weight_ == 0); assert(lfsr_data_size(data_) == 2); lfsr_rbyd_lookupnext(&lfs, &rbyd, 14, LFSR_TAG_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(3), 0, LFSR_DATA_BUF("unrelated", 9)), // make id0 with weight w1 LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xaa\xaa", 2)), // make id2 with weight w2 LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xbb\xbb", 2)), LFSR_RAT( LFSR_TAG_GROW, +1, LFSR_DATA_NULL()), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xbb\xbb", 2)), // make id5 with weight w3 LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xcc\xcc", 2)), LFSR_RAT( LFSR_TAG_GROW, +2, LFSR_DATA_NULL()), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xcc\xcc", 2)), // make id9 with weight w4 LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xdd\xdd", 2)), LFSR_RAT( LFSR_TAG_GROW, +3, LFSR_DATA_NULL()), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xdd\xdd", 2)), // make id14 with weight w5 LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xee\xee\xee\xee", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xee\xee", 2)), LFSR_RAT( LFSR_TAG_GROW, +4, LFSR_DATA_NULL()), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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_ATTR(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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF(names[perm[j] % 6], 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF(names[perm[j] % 6], 2)), LFSR_RAT( LFSR_TAG_GROW, +W-1, LFSR_DATA_NULL()), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(3), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF(names[perm[j] % 6], 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF(names[perm[j] % 6], 2)), LFSR_RAT( LFSR_TAG_GROW, +W-1, LFSR_DATA_NULL()), LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(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_ATTR(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_ATTR(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, LFS_M_RDWR, 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_RATS( LFSR_RAT( 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(lfsr_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfsr_rbyd_eoff(&rbyd)) => 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, lfsr_rbyd_eoff(&rbyd), NULL, false) => 0; lfsr_bd_flush(&lfs, NULL, false) => 0; lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_RATS( LFSR_RAT(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, LFS_M_RDWR, 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_RATS( LFSR_RAT( 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(lfsr_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfsr_rbyd_eoff(&rbyd)) => 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, lfsr_rbyd_eoff(&rbyd), NULL, false) => 0; lfsr_bd_flush(&lfs, NULL, false) => 0; lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_RATS( LFSR_RAT( 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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(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(lfsr_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfsr_rbyd_eoff(&rbyd)) => 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, lfsr_rbyd_eoff(&rbyd), NULL, false) => 0; lfsr_bd_flush(&lfs, NULL, false) => 0; lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_RATS( LFSR_RAT( LFSR_TAG_GROW | LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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, LFS_M_RDWR, 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_RATS( LFSR_RAT( 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(lfsr_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfsr_rbyd_eoff(&rbyd)) => 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, lfsr_rbyd_eoff(&rbyd), NULL, false) => 0; lfsr_bd_flush(&lfs, NULL, false) => 0; lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_RATS( LFSR_RAT(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, LFS_M_RDWR, 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_RATS( LFSR_RAT( 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(lfsr_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfsr_rbyd_eoff(&rbyd)) => 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, lfsr_rbyd_eoff(&rbyd), NULL, false) => 0; lfsr_bd_flush(&lfs, NULL, false) => 0; lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_RATS( LFSR_RAT( 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, LFS_M_RDWR, 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_RATS( LFSR_RAT( LFSR_TAG_ATTR(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(lfsr_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfsr_rbyd_eoff(&rbyd)) => 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, lfsr_rbyd_eoff(&rbyd), NULL, false) => 0; lfsr_bd_flush(&lfs, NULL, false) => 0; lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_RATS( LFSR_RAT( LFSR_TAG_GROW | LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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_ATTR(2), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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, LFS_M_RDWR, 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_RATS( LFSR_RAT( 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(lfsr_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfsr_rbyd_eoff(&rbyd)) => 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, lfsr_rbyd_eoff(&rbyd), NULL, false) => 0; lfsr_bd_flush(&lfs, NULL, false) => 0; lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_RATS( LFSR_RAT(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_RATS( LFSR_RAT( 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_rat_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, LFS_M_RDWR, 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_RATS( LFSR_RAT( 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(lfsr_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfsr_rbyd_eoff(&rbyd)) => 0; // try appending an rat 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, lfsr_rbyd_eoff(&rbyd), NULL, false) => 0; lfsr_bd_flush(&lfs, NULL, false) => 0; lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(1)); assert(rid_ == k*W+W-1); assert(weight_ == 0); assert(lfsr_data_size(data_) == 2); } } // now try removing the rat printf("--- removing: %d ---\n", j); lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_RATS( LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_ATTR(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_ATTR(1), &data) => LFS_ERR_NOENT; } } // and try putting the rat back just for good measure printf("--- appending: %d ---\n", j); lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(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_ATTR(1), &rid_, &tag_, &weight_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(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)' fuzz = 'SEED' # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, LFS_M_RDWR, 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 rat append/remove uint8_t op = TEST_PRNG(&prng) % 4; // choose an rid lfs_ssize_t rid = TEST_PRNG(&prng) % (count+1); // choose an rat 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 rat append/remove uint8_t op = TEST_PRNG(&prng) % 4; // choose an rid lfs_ssize_t rid = TEST_PRNG(&prng) % (count+1); // choose an rat 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_RATS( LFSR_RAT( 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_RATS( LFSR_RAT(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_RATS( LFSR_RAT( LFSR_TAG_ATTR(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_RATS( LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_ATTR(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_ATTR(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)' fuzz = 'SEED' # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, LFS_M_RDWR, 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_RATS( LFSR_RAT( 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_RATS( LFSR_RAT(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_RATS( LFSR_RAT(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_RATS( LFSR_RAT(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, LFS_M_RDWR, 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 rat a subtype based on its rid + SHIFT lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF(names[perm[j] % 6], 4)), LFSR_RAT( LFSR_TAG_ATTR((perm[j] + SHIFT) & 0x7f), 0, LFSR_DATA_BUF(names[perm[j] % 6], 2)))) => 0; } assert(rbyd.weight == N); // test that we can lookup each rat 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_ATTR, &tag_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR((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, LFS_M_RDWR, 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 rat a subtype based on its rid + SHIFT lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF(names[perm[j] % 6], 4)), LFSR_RAT( LFSR_TAG_ATTR((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(lfsr_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfsr_rbyd_eoff(&rbyd)) => 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, lfsr_rbyd_eoff(&rbyd), NULL, false) => 0; lfsr_bd_flush(&lfs, NULL, false) => 0; // remove with a wide tag lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATS( LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_SUB | LFSR_TAG_ATTR, 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_ATTR((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_ATTR, &tag_, &data_) => LFS_ERR_NOENT; } else { lfsr_rbyd_sublookup(&lfs, &rbyd, k, LFSR_TAG_ATTR, &tag_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR((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, LFS_M_RDWR, 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 rat a subtype based on its rid + SHIFT lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF(names[perm[j] % 6], 4)), LFSR_RAT( LFSR_TAG_ATTR((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(lfsr_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfsr_rbyd_eoff(&rbyd)) => 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, lfsr_rbyd_eoff(&rbyd), NULL, false) => 0; lfsr_bd_flush(&lfs, NULL, false) => 0; // replace with bitwise inverse lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATS( LFSR_RAT( LFSR_TAG_SUB | LFSR_TAG_ATTR(~(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_ATTR(~(k + SHIFT) & 0x7f)); assert(weight_ == 0); assert(lfsr_data_size(data_) == 3); } else { assert(rid_ == k); assert(tag_ == LFSR_TAG_ATTR((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_ATTR, &tag_, &data_) => 0; if (k == j) { assert(tag_ == LFSR_TAG_ATTR(~(k + SHIFT) & 0x7f)); assert(lfsr_data_size(data_) == 3); } else { assert(tag_ == LFSR_TAG_ATTR((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, LFS_M_RDWR, 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 rat a subtype based on its rid + SHIFT lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF(names[perm[j] % 6], 4)), LFSR_RAT( LFSR_TAG_ATTR(0x7f & (perm[j] + SHIFT)), 0, LFSR_DATA_BUF(names[perm[j] % 6], 2)), LFSR_RAT( LFSR_TAG_ATTR(0x80), 0, LFSR_DATA_BUF(names[perm[j] % 6], 1)))) => 0; } assert(rbyd.weight == N); // test that we can lookup each rat 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_ATTR, &tag_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR(0x7f & (j + SHIFT))); 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, LFS_M_RDWR, 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 rat a subtype based on its rid + SHIFT lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF(names[perm[j] % 6], 4)), LFSR_RAT( LFSR_TAG_ATTR(0x7f & (perm[j] + SHIFT)), 0, LFSR_DATA_BUF(names[perm[j] % 6], 2)), LFSR_RAT( LFSR_TAG_ATTR(0x80), 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(lfsr_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfsr_rbyd_eoff(&rbyd)) => 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, lfsr_rbyd_eoff(&rbyd), NULL, false) => 0; lfsr_bd_flush(&lfs, NULL, false) => 0; // remove with a wide tag lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATS( LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_SUB | LFSR_TAG_ATTR, 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_ATTR(0x7f & (k + SHIFT))); 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_ATTR(0x80)); 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_ATTR, &tag_, &data_) => LFS_ERR_NOENT; } else { lfsr_rbyd_sublookup(&lfs, &rbyd, k, LFSR_TAG_ATTR, &tag_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR((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, LFS_M_RDWR, 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 rat a subtype based on its rid + SHIFT lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF(names[perm[j] % 6], 4)), LFSR_RAT( LFSR_TAG_ATTR(0x7f & (perm[j] + SHIFT)), 0, LFSR_DATA_BUF(names[perm[j] % 6], 2)), LFSR_RAT( LFSR_TAG_ATTR(0x80), 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(lfsr_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfsr_rbyd_eoff(&rbyd)) => 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, lfsr_rbyd_eoff(&rbyd), NULL, false) => 0; lfsr_bd_flush(&lfs, NULL, false) => 0; // replace with bitwise inverse lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATS( LFSR_RAT( LFSR_TAG_SUB | LFSR_TAG_ATTR(~(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_ATTR(0x7f & ~(k + SHIFT))); assert(weight_ == 0); assert(lfsr_data_size(data_) == 3); } else { assert(rid_ == k); assert(tag_ == LFSR_TAG_ATTR(0x7f & (k + SHIFT))); 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_ATTR(0x80)); 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_ATTR, &tag_, &data_) => 0; if (k == j) { assert(tag_ == LFSR_TAG_ATTR(~(k + SHIFT) & 0x7f)); assert(lfsr_data_size(data_) == 3); } else { assert(tag_ == LFSR_TAG_ATTR((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, LFS_M_RDWR, 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 rat a subtype based on its rid + SHIFT lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR((perm[j] + SHIFT) & 0x7f), +1, LFSR_DATA_BUF(names[perm[j] % 6], 4)))) => 0; } assert(rbyd.weight == N); // test that we can lookup each rat 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_ATTR, &tag_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR((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, LFS_M_RDWR, 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 rat a subtype based on its rid + SHIFT lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR((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(lfsr_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfsr_rbyd_eoff(&rbyd)) => 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, lfsr_rbyd_eoff(&rbyd), NULL, false) => 0; lfsr_bd_flush(&lfs, NULL, false) => 0; // remove with a wide tag lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATS( LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_SUB | LFSR_TAG_ATTR, 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_ATTR((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_ATTR((k+1 + SHIFT) & 0x7f)); assert(weight_ == 1); assert(lfsr_data_size(data_) == 4); } else { assert(rid_ == k); assert(tag_ == LFSR_TAG_ATTR((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_ATTR, &tag_, &data_) => LFS_ERR_NOENT; } else { lfsr_rbyd_sublookup(&lfs, &rbyd, k, LFSR_TAG_ATTR, &tag_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR((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, LFS_M_RDWR, 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 rat a subtype based on its rid + SHIFT lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR((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(lfsr_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfsr_rbyd_eoff(&rbyd)) => 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, lfsr_rbyd_eoff(&rbyd), NULL, false) => 0; lfsr_bd_flush(&lfs, NULL, false) => 0; // replace with bitwise inverse lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATS( LFSR_RAT( LFSR_TAG_SUB | LFSR_TAG_ATTR(~(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_ATTR(~(k + SHIFT) & 0x7f)); assert(weight_ == 1); assert(lfsr_data_size(data_) == 6); } else { assert(rid_ == k); assert(tag_ == LFSR_TAG_ATTR((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_ATTR, &tag_, &data_) => 0; if (k == j) { assert(tag_ == LFSR_TAG_ATTR(~(k + SHIFT) & 0x7f)); assert(lfsr_data_size(data_) == 6); } else { assert(tag_ == LFSR_TAG_ATTR((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, LFS_M_RDWR, 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 rat a subtype based on its rid + SHIFT lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF(names[perm[j] % 6], 4)), LFSR_RAT( LFSR_TAG_ATTR((perm[j] + SHIFT) & 0x7f), 0, LFSR_DATA_BUF(names[perm[j] % 6], 2)))) => 0; } assert(rbyd.weight == N); // a supwide rat 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, LFS_M_RDWR, 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 rat a subtype based on its rid + SHIFT lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF(names[perm[j] % 6], 4)), LFSR_RAT( LFSR_TAG_ATTR((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(lfsr_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfsr_rbyd_eoff(&rbyd)) => 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, lfsr_rbyd_eoff(&rbyd), NULL, false) => 0; lfsr_bd_flush(&lfs, NULL, false) => 0; // remove with a wide tag lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATS( LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_SUP | LFSR_TAG_ATTR, 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_ATTR((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_ATTR, &tag_, &data_) => LFS_ERR_NOENT; } else { lfsr_rbyd_sublookup(&lfs, &rbyd, k, LFSR_TAG_ATTR, &tag_, &data_) => 0; assert(tag_ == LFSR_TAG_ATTR((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, LFS_M_RDWR, 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 rat a subtype based on its rid + SHIFT lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATS( LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF(names[perm[j] % 6], 4)), LFSR_RAT( LFSR_TAG_ATTR((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(lfsr_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfsr_rbyd_eoff(&rbyd)) => 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, lfsr_rbyd_eoff(&rbyd), NULL, false) => 0; lfsr_bd_flush(&lfs, NULL, false) => 0; // replace with bitwise inverse lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATS( LFSR_RAT( LFSR_TAG_SUP | LFSR_TAG_ATTR(~(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_ATTR(~(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_ATTR((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_ATTR, &tag_, &data_) => 0; if (k == j) { assert(tag_ == LFSR_TAG_ATTR(~(k + SHIFT) & 0x7f)); assert(lfsr_data_size(data_) == 3); } else { assert(tag_ == LFSR_TAG_ATTR((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, LFS_M_RDWR, 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_bd_erase(&lfs, rbyd.blocks[0]) => 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(0), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_ATTR(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_ATTR(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_ATTR(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, LFS_M_RDWR, 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_bd_erase(&lfs, rbyd.blocks[0]) => 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(0), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(2), 0, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_ATTR(0), 0, LFSR_DATA_NULL()))) => 0; assert(rbyd.weight == 0); // remove a neighbor to the hole lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_ATTR(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_ATTR(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_ATTR(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, LFS_M_RDWR, 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_bd_erase(&lfs, rbyd.blocks[0]) => 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(0), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_ATTR(0), 0, LFSR_DATA_NULL()))) => 0; assert(rbyd.weight == 2); // delete a neighbor to the hole lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATS( LFSR_RAT(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, LFS_M_RDWR, 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_bd_erase(&lfs, rbyd.blocks[0]) => 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(0x00), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(0x01), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_ATTR(0x80), 0, LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)), LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_ATTR(0), 0, LFSR_DATA_NULL()))) => 0; assert(rbyd.weight == 0); // subwide replace a neighbor to the hole lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_SUB | LFSR_TAG_ATTR(0x02), 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_ATTR(0x02)); 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_ATTR(2)+1, &rid_, &tag_, &weight_, &data_) => 0; assert(rid_ == -1); assert(tag_ == LFSR_TAG_ATTR(0x80)); 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_ATTR(0x80)+1, &rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT; ''' [cases.test_rbyd_unreachable_hole_supwide] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, LFS_M_RDWR, 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_bd_erase(&lfs, rbyd.blocks[0]) => 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_ATTR(0), 0, LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), LFSR_RAT( LFSR_TAG_ATTR(1), 0, LFSR_DATA_BUF("\xbb\xbb\xbb\xbb", 4)), LFSR_RAT( LFSR_TAG_REG, +1, LFSR_DATA_BUF("\xdd\xdd\xdd\xdd", 4)))) => 0; lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_RM | LFSR_TAG_ATTR(0), 0, LFSR_DATA_NULL()))) => 0; assert(rbyd.weight == 1); // supwide replace a neighbor to the hole lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATS( LFSR_RAT( LFSR_TAG_SUP | LFSR_TAG_ATTR(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_ATTR(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_ATTR(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; '''