diff --git a/lfs.c b/lfs.c index 558f9203..994cd08b 100644 --- a/lfs.c +++ b/lfs.c @@ -575,9 +575,10 @@ static inline lfs_rtag_t lfs_rtag_isparallel(lfs_rtag_t a, lfs_rtag_t b) { return (a & 0x2) == (b & 0x2); } -static inline lfs_srtag_t lfs_rtag_weight(lfs_rtag_t tag) { - return tag >> 3; -} +// TODO rm +//static inline lfs_srtag_t lfs_rtag_weight(lfs_rtag_t tag) { +// return tag >> 3; +//} static inline lfs_rtag_t lfs_rtag_weight_(lfs_rtag_t tag) { return tag & ~0x7; @@ -587,23 +588,23 @@ static inline lfs_rtag_t lfs_rtag_merge(lfs_rtag_t a, lfs_rtag_t b) { return a + (b & ~0x7); } -static inline lfs_srtag_t lfs_rtag_weight_lt(lfs_rtag_t tag, uint16_t count) { - (void)count; - return lfs_rtag_weight(tag); -} +//static inline lfs_srtag_t lfs_rtag_weight_lt(lfs_rtag_t tag, uint16_t count) { +// (void)count; +// return lfs_rtag_weight(tag); +//} +// +//static inline lfs_srtag_t lfs_rtag_weight_gt(lfs_rtag_t tag, uint16_t count) { +// return (((lfs_srtag_t)count) << 12)-1 - lfs_rtag_weight(tag); +//} -static inline lfs_srtag_t lfs_rtag_weight_gt(lfs_rtag_t tag, uint16_t count) { - return (((lfs_srtag_t)count) << 12)-1 - lfs_rtag_weight(tag); -} - -static inline bool lfs_rtag_follow(lfs_rtag_t alt, - lfs_srtag_t lt, lfs_srtag_t gt) { - if (lfs_rtag_islt(alt)) { - return lfs_rtag_weight(alt) > lt; - } else { - return lfs_rtag_weight(alt) > gt; - } -} +//static inline bool lfs_rtag_follow(lfs_rtag_t alt, +// lfs_srtag_t lt, lfs_srtag_t gt) { +// if (lfs_rtag_islt(alt)) { +// return lfs_rtag_weight(alt) > lt; +// } else { +// return lfs_rtag_weight(alt) > gt; +// } +//} static inline bool lfs_rtag_follow_(lfs_rtag_t alt, lfs_rtag_t lower, lfs_rtag_t upper, lfs_rtag_t tag) { @@ -615,13 +616,13 @@ static inline bool lfs_rtag_follow_(lfs_rtag_t alt, } } -static inline lfs_rtag_t lfs_rtag_flip( - lfs_rtag_t alt, lfs_rtag_t lt, lfs_rtag_t gt) { - return LFS_MKRALT_( - lfs_rtag_isred(alt), - !lfs_rtag_isgt(alt), - (lt+gt+1) - lfs_rtag_weight(alt)); -} +//static inline lfs_rtag_t lfs_rtag_flip( +// lfs_rtag_t alt, lfs_rtag_t lt, lfs_rtag_t gt) { +// return LFS_MKRALT_( +// lfs_rtag_isred(alt), +// !lfs_rtag_isgt(alt), +// (lt+gt+1) - lfs_rtag_weight(alt)); +//} static inline lfs_rtag_t lfs_rtag_flip_(lfs_rtag_t alt, lfs_rtag_t lower, lfs_rtag_t upper) { @@ -631,14 +632,14 @@ static inline lfs_rtag_t lfs_rtag_flip_(lfs_rtag_t alt, (upper-lower) - lfs_rtag_weight_(alt)); } -static inline void lfs_rtag_trim(lfs_rtag_t alt, - lfs_srtag_t *lt, lfs_srtag_t *gt) { - if (lfs_rtag_islt(alt)) { - *lt = *lt - lfs_rtag_weight(alt); - } else { - *gt = *gt - lfs_rtag_weight(alt); - } -} +//static inline void lfs_rtag_trim(lfs_rtag_t alt, +// lfs_srtag_t *lt, lfs_srtag_t *gt) { +// if (lfs_rtag_islt(alt)) { +// *lt = *lt - lfs_rtag_weight(alt); +// } else { +// *gt = *gt - lfs_rtag_weight(alt); +// } +//} static inline void lfs_rtag_trim_(lfs_rtag_t alt, lfs_rtag_t *lower, lfs_rtag_t *upper) { @@ -649,14 +650,14 @@ static inline void lfs_rtag_trim_(lfs_rtag_t alt, } } -static inline void lfs_rtag_untrim(lfs_rtag_t alt, - lfs_srtag_t *lt, lfs_srtag_t *gt) { - if (lfs_rtag_islt(alt)) { - *lt = *lt + lfs_rtag_weight(alt); - } else { - *gt = *gt + lfs_rtag_weight(alt); - } -} +//static inline void lfs_rtag_untrim(lfs_rtag_t alt, +// lfs_srtag_t *lt, lfs_srtag_t *gt) { +// if (lfs_rtag_islt(alt)) { +// *lt = *lt + lfs_rtag_weight(alt); +// } else { +// *gt = *gt + lfs_rtag_weight(alt); +// } +//} static inline void lfs_rtag_untrim_(lfs_rtag_t alt, lfs_rtag_t *lower, lfs_rtag_t *upper) { @@ -1035,12 +1036,11 @@ static lfs_ssize_t lfs_rbyd_readtag(lfs_t *lfs, *tag = 0; // read a pair of leb128s - uint8_t buffer[2*4]; + // + // note we force leb decoding to overflow when truncated + uint8_t buffer[2*4] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; lfs_size_t i = 0; - // force leb decoding to overflow when truncated - memset(buffer, 0xff, 2*4); - // TODO allow different hint for lookup? bench this? does our hint work backwards? // TODO should lfs_bd_read allow a range for reads? int err = lfs_bd_read(lfs, @@ -1388,6 +1388,7 @@ static int lfs_rbyd_prog(lfs_t *lfs, lfs_rbyd_t *rbyd_, static int lfs_rbyd_progtag(lfs_t *lfs, lfs_rbyd_t *rbyd_, lfs_rtag_t tag, lfs_size_t size, uint32_t *crc) { // convert to on-disk repr + LFS_ASSERT(lfs_rtag_isvalid(tag)); tag <<= 1; // make sure to include the parity of the current crc @@ -1770,125 +1771,62 @@ stem:; } // split leaf nodes? - lfs_rtag_t alt; - if (lfs_rtag_type1(tag) == LFS_TYPE1_DELETE) { - // TODO why are both paths never taken?? - if (lfs_rtag_weight_(lower_tag_) - < lfs_rtag_weight_(tag & ~0x7fff)) { - alt = LFS_MKRALT__(B, LT, - (lfs_rtag_weight_(lower_tag_)+0x8) - lower_lower); + // + // note we bias the weights here so that lfs_rbyd_lookup + // always finds the next biggest tag + lfs_rtag_t alt = 0; + lfs_off_t jump = 0; - // TODO can we rededuplicate this? - int err = lfs_rbyd_p_push(lfs, rbyd_, - p_alts, p_jumps, - alt, lower_branch); - if (err) { - return err; - } + if (lfs_rtag_isrm(lower_tag_)) { + // no split needed, prune the removed tag - // lfs_rbyd_p_red(p_alts, p_jumps); these should not be here - } else + } else if (lfs_rtag_type1(tag) == LFS_TYPE1_CREATE + && lfs_rtag_weight_(upper_tag_) >= lfs_rtag_weight_(tag & ~0x7fff)) { + // increase biased weight when creating + alt = LFS_MKRALT__(B, GT, + (upper_upper+0x8000) - (lfs_rtag_weight_(tag)+0x8)); + jump = upper_branch; - if (lfs_rtag_weight_(upper_tag_) - >= lfs_rtag_weight_(tag & ~0x7fff)+0x8000) { - alt = LFS_MKRALT__(B, GT, - upper_upper - (lfs_rtag_weight_(lower_tag_)+0x8)); + } else if (lfs_rtag_type1(tag) == LFS_TYPE1_DELETE + && lfs_rtag_weight_(upper_tag_) >= lfs_rtag_weight_(tag & ~0x7fff)+0x8000) { + // decrease biased weight when deleting + alt = LFS_MKRALT__(B, GT, + upper_upper-0x8000 - lower_lower); + jump = upper_branch; - // TODO can we rededuplicate this? - int err = lfs_rbyd_p_push(lfs, rbyd_, - p_alts, p_jumps, - alt, upper_branch); - if (err) { - return err; - } + } else if (lfs_rtag_type1(tag) != LFS_TYPE1_DELETE + && lfs_rtag_isrm(tag) + && lfs_rtag_weight_(upper_tag_) > lfs_rtag_weight_(tag)) { + // hide our tag during removes + alt = LFS_MKRALT__(B, GT, + upper_upper - lower_lower); + jump = upper_branch; - // lfs_rbyd_p_red(p_alts, p_jumps); these should not be here + } else if (!lfs_rtag_isrm(tag) + && lfs_rtag_weight_(upper_tag_) > lfs_rtag_weight_(tag)) { + // split greater than + alt = LFS_MKRALT__(B, GT, + upper_upper - (lfs_rtag_weight_(tag)+0x8)); + jump = upper_branch; + + } else if (lfs_rtag_weight_(lower_tag_) < lfs_rtag_weight_(tag)) { + // split less than, this is consistent for all appends and only happens + // when appending to the end of the tree + alt = LFS_MKRALT__(B, LT, + (lfs_rtag_weight_(lower_tag_)+0x8) - lower_lower); + jump = lower_branch; + } + + if (alt) { + int err = lfs_rbyd_p_push(lfs, rbyd_, + p_alts, p_jumps, + alt, jump); + if (err) { + return err; } - } else if (lfs_rtag_isrm(tag)) { - // TODO why are both paths never taken?? - if (lfs_rtag_weight_(lower_tag_) - < lfs_rtag_weight_(tag & ~0x1)) { - alt = LFS_MKRALT__(B, LT, - (lfs_rtag_weight_(lower_tag_)+0x8) - lower_lower); - - // TODO can we rededuplicate this? - int err = lfs_rbyd_p_push(lfs, rbyd_, - p_alts, p_jumps, - alt, lower_branch); - if (err) { - return err; - } - - // lfs_rbyd_p_red(p_alts, p_jumps); these should not be here - } else - - if (lfs_rtag_weight_(upper_tag_) - >= lfs_rtag_weight_(tag & ~0x1)+0x8) { - // remove found a tag - if (lfs_rtag_weight(lower_tag_) == lfs_rtag_weight(tag)) { - alt = LFS_MKRALT__(B, GT, - upper_upper - (lfs_rtag_weight_(lower_tag_)+0x8)+0x8); - // remove found no tag? - } else { - alt = LFS_MKRALT__(B, GT, - upper_upper - lower_lower); - } - - // TODO can we rededuplicate this? - int err = lfs_rbyd_p_push(lfs, rbyd_, - p_alts, p_jumps, - alt, upper_branch); - if (err) { - return err; - } - } - } else if (lfs_rtag_type1(tag) == LFS_TYPE1_CREATE) { - // inserting a new id? - LFS_ASSERT(!diverged); - // TODO rm should probably be handled generally - if (!lfs_rtag_isrm(lower_tag_)) { - // note we bias the weights here so that lfs_rbyd_lookup - // always finds the next biggest tag - if (lfs_rtag_weight(lower_tag_) - < lfs_rtag_weight(tag & ~0x7fff)) { - alt = LFS_MKRALT__(B, LT, - (lfs_rtag_weight_(lower_tag_)+0x8) - lower_lower); - } else { - alt = LFS_MKRALT__(B, GT, - (lower_upper+0x8000) - (lfs_rtag_weight_(tag)+0x8)); - } - - int err = lfs_rbyd_p_push(lfs, rbyd_, - p_alts, p_jumps, - alt, lower_branch); - if (err) { - return err; - } - - lfs_rbyd_p_red(p_alts, p_jumps); - } - } else { - LFS_ASSERT(!diverged); - // TODO use weights here? - if (lfs_rtag_weight_(lower_tag_) != lfs_rtag_weight_(tag) - && !lfs_rtag_isrm(lower_tag_)) { - // note we bias the weights here so that lfs_rbyd_lookup - // always finds the next biggest tag - if (lfs_rtag_weight_(lower_tag_) < lfs_rtag_weight_(tag)) { - alt = LFS_MKRALT__(B, LT, - (lfs_rtag_weight_(lower_tag_)+0x8) - lower_lower); - } else { - alt = LFS_MKRALT__(B, GT, - lower_upper - (lfs_rtag_weight_(tag)+0x8)); - } - - int err = lfs_rbyd_p_push(lfs, rbyd_, - p_alts, p_jumps, - alt, lower_branch); - if (err) { - return err; - } + if (!lfs_rtag_isrm(tag)) { + // introduce a red edge lfs_rbyd_p_red(p_alts, p_jumps); } } diff --git a/tests/test_rbyd.toml b/tests/test_rbyd.toml index 6d09125a..3ee189fd 100644 --- a/tests/test_rbyd.toml +++ b/tests/test_rbyd.toml @@ -1969,6 +1969,7 @@ code = ''' lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false, rbyd.block, 0, backup_block, rbyd.off) => 0; + lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRRMATTR(UATTR, j+1, 0, NULL)) => 0; @@ -2398,6 +2399,7 @@ code = ''' lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false, rbyd.block, 0, backup_block, rbyd.off) => 0; + lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false) => 0; // remove each tag in permutation order for (unsigned j = 0; j < N; j++) { @@ -2529,6 +2531,7 @@ code = ''' lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false, rbyd.block, 0, backup_block, rbyd.off) => 0; + lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false) => 0; // remove lfs_rbyd_commit(&lfs, &rbyd, @@ -3684,6 +3687,7 @@ code = ''' lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false, rbyd.block, 0, backup_block, rbyd.off) => 0; + lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(DELETE, 0, j+1, NULL, 0, NULL)) => 0; @@ -3738,6 +3742,7 @@ code = ''' [cases.test_rbyd_delete_range_permutations] defines.N = 'range(1, 7)' +defines.M = 'range(1, 4)' in = 'lfs.c' code = ''' lfs_t lfs; @@ -3801,9 +3806,13 @@ code = ''' lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, id+1, names[perm[j] % 6], 4, - // note uattrs have a smaller size - LFS_MKRATTR(UATTR, 1, id+1, names[perm[j] % 6], 2, - NULL))) => 0; + NULL)) => 0; + // note uattrs have a smaller size to help debugging + for (unsigned u = 0; u < M; u++) { + lfs_rbyd_commit(&lfs, &rbyd, + LFS_MKRATTR(UATTR, u+1, id+1, names[perm[j] % 6], 2, + NULL)) => 0; + } } assert(rbyd.count == N); @@ -3822,6 +3831,7 @@ code = ''' lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false, rbyd.block, 0, backup_block, rbyd.off) => 0; + lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(DELETE, 0, j+1, NULL, 0, NULL)) => 0; @@ -3837,12 +3847,14 @@ code = ''' assert(memcmp(buffer, names[k % 6], 4) == 0); } - lfs_rbyd_get(&lfs, &rbyd, - LFS_MKRTAG(UATTR, 1, k+1), buffer, 4) => 2; - if (k >= j) { - assert(memcmp(buffer, names[(k+1) % 6], 2) == 0); - } else { - assert(memcmp(buffer, names[k % 6], 2) == 0); + for (unsigned u = 0; u < M; u++) { + lfs_rbyd_get(&lfs, &rbyd, + LFS_MKRTAG(UATTR, u+1, k+1), buffer, 4) => 2; + if (k >= j) { + assert(memcmp(buffer, names[(k+1) % 6], 2) == 0); + } else { + assert(memcmp(buffer, names[k % 6], 2) == 0); + } } } lfs_rbyd_get(&lfs, &rbyd, @@ -3877,7 +3889,7 @@ code = ''' // test that tree is self-balancing, we should be strictly bounded // by height <= 2*log(n)+1, assume tags are roughly ~8 bytes - lfs_size_t n = 1 + 2*N + 1; + lfs_size_t n = 1 + N+N*M + 1; printf("worst size: %u B (N=%u, estimate=%u)\n", worst_size, n, 8*n*(2*lfs_nlog2(n)+1)); printf("avg height: %u B (N=%u, estimate=%u)\n", @@ -4200,6 +4212,7 @@ code = ''' lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false, rbyd.block, 0, backup_block, rbyd.off) => 0; + lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false) => 0; // delete each id in permutation order for (unsigned j = 0; j < N; j++) { @@ -4274,6 +4287,7 @@ code = ''' [cases.test_rbyd_delete_all_range_permutations] defines.N = 'range(1, 7)' +defines.M = 'range(1, 4)' in = 'lfs.c' code = ''' lfs_t lfs; @@ -4309,8 +4323,13 @@ code = ''' for (unsigned j = 0; j < N; j++) { lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, j+1, names[j % 6], 4, - LFS_MKRATTR(UATTR, 1, j+1, names[j % 6], 2, - NULL))) => 0; + NULL)) => 0; + // note uattrs have a smaller size to help debugging + for (unsigned u = 0; u < M; u++) { + lfs_rbyd_commit(&lfs, &rbyd, + LFS_MKRATTR(UATTR, u+1, j+1, names[j % 6], 2, + NULL)) => 0; + } } assert(rbyd.count == N); @@ -4345,6 +4364,7 @@ code = ''' lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false, rbyd.block, 0, backup_block, rbyd.off) => 0; + lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false) => 0; // delete each id in permutation order for (unsigned j = 0; j < N; j++) { @@ -4372,8 +4392,12 @@ code = ''' // try resuming from all tags being removed lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, 1, "\xaa\xaa\xaa\xaa\xaa\xaa", 6, - LFS_MKRATTR(UATTR, 1, 1, "\xaa\xaa\xaa", 3, - NULL))) => 0; + NULL)) => 0; + for (unsigned u = 0; u < M; u++) { + lfs_rbyd_commit(&lfs, &rbyd, + LFS_MKRATTR(UATTR, u+1, 1, "\xaa\xaa\xaa", 3, + NULL)) => 0; + } assert(rbyd.count == 1); lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; @@ -4382,10 +4406,12 @@ code = ''' LFS_MKRTAG(CREATEREG, 0, 1), buffer, 6) => 6; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa\xaa\xaa", 6) == 0); - lfs_rbyd_get(&lfs, &rbyd, - LFS_MKRTAG(UATTR, 1, 1), buffer, 6) - => 3; - assert(memcmp(buffer, "\xaa\xaa\xaa", 3) == 0); + for (unsigned u = 0; u < M; u++) { + lfs_rbyd_get(&lfs, &rbyd, + LFS_MKRTAG(UATTR, u+1, 1), buffer, 6) + => 3; + assert(memcmp(buffer, "\xaa\xaa\xaa", 3) == 0); + } lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 6) => LFS_ERR_NOENT; @@ -4417,7 +4443,7 @@ code = ''' // test that tree is self-balancing, we should be strictly bounded // by height <= 2*log(n)+1, assume tags are roughly ~8 bytes - lfs_size_t n = 1 + 2*N + N + 2; + lfs_size_t n = 1 + N+N*M + N + 1+M; printf("worst size: %u B (N=%u, estimate=%u)\n", worst_size, n, 8*n*(2*lfs_nlog2(n)+1)); printf("avg height: %u B (N=%u, estimate=%u)\n", @@ -4510,6 +4536,7 @@ code = ''' lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false, rbyd.block, 0, backup_block, rbyd.off) => 0; + lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false) => 0; // delete lfs_rbyd_commit(&lfs, &rbyd, @@ -4580,6 +4607,7 @@ code = ''' [cases.test_rbyd_delete_create_range_permutations] defines.N = 'range(1, 6)' +defines.M = 'range(1, 4)' in = 'lfs.c' code = ''' lfs_t lfs; @@ -4643,8 +4671,13 @@ code = ''' lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, id+1, names[perm[j] % 6], 4, - LFS_MKRATTR(UATTR, 1, id+1, names[perm[j] % 6], 2, - NULL))) => 0; + NULL)) => 0; + // note uattrs have a smaller size to help debugging + for (unsigned u = 0; u < M; u++) { + lfs_rbyd_commit(&lfs, &rbyd, + LFS_MKRATTR(UATTR, u+1, id+1, names[perm[j] % 6], 2, + NULL)) => 0; + } } assert(rbyd.count == N); @@ -4664,6 +4697,7 @@ code = ''' lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false, rbyd.block, 0, backup_block, rbyd.off) => 0; + lfs_bd_flush(&lfs, &lfs.pcache, &lfs.rcache, false) => 0; // delete lfs_rbyd_commit(&lfs, &rbyd, @@ -4675,8 +4709,12 @@ code = ''' // is still usable lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, l+1, names[l % 6], 6, - LFS_MKRATTR(UATTR, 1, l+1, names[l % 6], 3, - NULL))) => 0; + NULL)) => 0; + for (unsigned u = 0; u < M; u++) { + lfs_rbyd_commit(&lfs, &rbyd, + LFS_MKRATTR(UATTR, u+1, l+1, names[l % 6], 3, + NULL)) => 0; + } assert(rbyd.count == N); lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; @@ -4698,21 +4736,23 @@ code = ''' assert(memcmp(buffer, names[expected % 6], 4) == 0); } - size = lfs_rbyd_get(&lfs, &rbyd, - LFS_MKRTAG(UATTR, 1, k+1), buffer, 6); - if (k == l) { - assert(size == 3); - assert(memcmp(buffer, names[l % 6], 3) == 0); - } else { - uint16_t expected = k; - if (expected > l) { - expected -= 1; + for (unsigned u = 0; u < M; u++) { + size = lfs_rbyd_get(&lfs, &rbyd, + LFS_MKRTAG(UATTR, u+1, k+1), buffer, 6); + if (k == l) { + assert(size == 3); + assert(memcmp(buffer, names[l % 6], 3) == 0); + } else { + uint16_t expected = k; + if (expected > l) { + expected -= 1; + } + if (expected >= j) { + expected += 1; + } + assert(size == 2); + assert(memcmp(buffer, names[expected % 6], 2) == 0); } - if (expected >= j) { - expected += 1; - } - assert(size == 2); - assert(memcmp(buffer, names[expected % 6], 2) == 0); } } @@ -4742,7 +4782,7 @@ code = ''' // test that tree is self-balancing, we should be strictly bounded // by height <= 2*log(n)+1, assume tags are roughly ~8 bytes - lfs_size_t n = 1 + N + 1 + 2; + lfs_size_t n = 1 + N+N*M + 2 + 1+M; printf("worst size: %u B (N=%u, estimate=%u)\n", worst_size, n, 8*n*(2*lfs_nlog2(n)+1)); printf("avg height: %u B (N=%u, estimate=%u)\n",