Merged sprout and shrub carving paths
Noticed a lot of duplicate conditions, so tried merging these two code
paths. This does risk a difficult to read/maintain function, since there
are some rather tricky subtleties with the sprout -> shrub transition.
On the other hand, the code reuse does mean less conditions to worry
about.
Merging these code paths also saves a bit of code:
code stack
before: 30960 2256
after: 30700 (-0.8%) 2256 (+0.0%)
This commit is contained in:
@@ -9209,100 +9209,13 @@ static int lfsr_file_carveinlined(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
lfsr_data_t *datas_ = scratch_datas;
|
lfsr_data_t *datas_ = scratch_datas;
|
||||||
*datas_++ = data;
|
*datas_++ = data;
|
||||||
|
|
||||||
|
// TODO what happens if another driver wrote a zero-weight shrub? need
|
||||||
|
// to test this...
|
||||||
|
|
||||||
// keep track of how our changes affect our estimate
|
// keep track of how our changes affect our estimate
|
||||||
lfs_off_t estimate;
|
lfs_off_t estimate = (!lfsr_file_hasshrub(file))
|
||||||
|
? 0
|
||||||
// have a sprout/null?
|
: file->inlined.u.shrub.estimate;
|
||||||
// TODO should we catch when we can stay inlined?
|
|
||||||
if (!lfsr_file_hasshrub(file)) {
|
|
||||||
estimate = 0;
|
|
||||||
|
|
||||||
// left data? this may create a hole
|
|
||||||
if (pos > 0) {
|
|
||||||
// can coalesce?
|
|
||||||
if (lfsr_data_size(&file->inlined.u.data) >= pos
|
|
||||||
&& pos+weight+delta <= lfs->cfg->coalesce_size) {
|
|
||||||
scratch_datas[0] = LFSR_DATA_DISK(
|
|
||||||
file->inlined.u.data.u.disk.block,
|
|
||||||
file->inlined.u.data.u.disk.off,
|
|
||||||
pos);
|
|
||||||
scratch_datas[1] = data;
|
|
||||||
datas_ = &scratch_datas[2];
|
|
||||||
data = lfsr_data_fromcat(&scratch_datas[0], 2);
|
|
||||||
weight += pos;
|
|
||||||
pos = 0;
|
|
||||||
|
|
||||||
// need to carve
|
|
||||||
} else {
|
|
||||||
*attrs_++ = LFSR_ATTR(0,
|
|
||||||
SHRUB(INLINED), +pos, DISK(
|
|
||||||
file->inlined.u.data.u.disk.block,
|
|
||||||
file->inlined.u.data.u.disk.off,
|
|
||||||
lfs_min32(
|
|
||||||
lfsr_data_size(&file->inlined.u.data),
|
|
||||||
pos)));
|
|
||||||
estimate += LFSR_ATTR_ESTIMATE
|
|
||||||
+ lfs_min32(
|
|
||||||
lfsr_data_size(&file->inlined.u.data),
|
|
||||||
pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// right data? this may also create a hole if delta > 0
|
|
||||||
if (lfsr_data_size(&file->inlined.u.data) > pos + weight) {
|
|
||||||
// can coalesce?
|
|
||||||
if (lfsr_data_size(&data) == weight + delta
|
|
||||||
&& lfsr_data_size(&data)
|
|
||||||
+ lfsr_data_size(&file->inlined.u.data)
|
|
||||||
- (pos + weight)
|
|
||||||
<= lfs->cfg->coalesce_size) {
|
|
||||||
*datas_++ = LFSR_DATA_DISK(
|
|
||||||
file->inlined.u.data.u.disk.block,
|
|
||||||
file->inlined.u.data.u.disk.off
|
|
||||||
+ (pos + weight),
|
|
||||||
lfsr_data_size(&file->inlined.u.data)
|
|
||||||
- (pos + weight));
|
|
||||||
data = lfsr_data_fromcat(
|
|
||||||
scratch_datas,
|
|
||||||
datas_ - scratch_datas);
|
|
||||||
weight += lfsr_data_size(&file->inlined.u.data)
|
|
||||||
- (pos + weight);
|
|
||||||
|
|
||||||
// need to carve
|
|
||||||
} else {
|
|
||||||
*attrs_++ = LFSR_ATTR(pos,
|
|
||||||
SHRUB(INLINED), +lfsr_data_size(&file->inlined.u.data)
|
|
||||||
- (pos + weight),
|
|
||||||
DISK(
|
|
||||||
file->inlined.u.data.u.disk.block,
|
|
||||||
file->inlined.u.data.u.disk.off
|
|
||||||
+ (pos + weight),
|
|
||||||
lfsr_data_size(&file->inlined.u.data)
|
|
||||||
- (pos + weight)));
|
|
||||||
estimate += LFSR_ATTR_ESTIMATE
|
|
||||||
+ lfsr_data_size(&file->inlined.u.data)
|
|
||||||
- (pos + weight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// append our data
|
|
||||||
if (weight + delta > 0) {
|
|
||||||
*attrs_++ = LFSR_ATTR(pos,
|
|
||||||
SHRUB(INLINED), +weight + delta, DATA(data));
|
|
||||||
estimate += LFSR_ATTR_ESTIMATE
|
|
||||||
+ lfsr_data_size(&data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// have a shrub?
|
|
||||||
} else {
|
|
||||||
// TODO what if another driver wrote a zero-weight shrub? need to
|
|
||||||
// test this
|
|
||||||
//
|
|
||||||
// this should never happen, every route to zero-weight shrub
|
|
||||||
// should revert to an inlined file
|
|
||||||
LFS_ASSERT(file->inlined.u.rbyd.weight > 0);
|
|
||||||
|
|
||||||
estimate = file->inlined.u.shrub.estimate;
|
|
||||||
|
|
||||||
lfs_soff_t left_overlap = 0;
|
lfs_soff_t left_overlap = 0;
|
||||||
lfs_soff_t right_overlap = 0;
|
lfs_soff_t right_overlap = 0;
|
||||||
@@ -9310,9 +9223,14 @@ static int lfsr_file_carveinlined(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
// has left sibling?
|
// has left sibling?
|
||||||
if (pos > 0) {
|
if (pos > 0) {
|
||||||
lfsr_srid_t left_rid;
|
lfsr_srid_t left_rid;
|
||||||
lfsr_tag_t left_tag;
|
|
||||||
lfsr_rid_t left_weight;
|
lfsr_rid_t left_weight;
|
||||||
lfsr_data_t left_data;
|
lfsr_data_t left_data;
|
||||||
|
if (!lfsr_file_hasshrub(file)) {
|
||||||
|
left_rid = lfsr_data_size(&file->inlined.u.data)-1;
|
||||||
|
left_weight = lfsr_data_size(&file->inlined.u.data);
|
||||||
|
left_data = file->inlined.u.data;
|
||||||
|
} else {
|
||||||
|
lfsr_tag_t left_tag;
|
||||||
int err = lfsr_rbyd_lookupnext(lfs, &file->inlined.u.rbyd,
|
int err = lfsr_rbyd_lookupnext(lfs, &file->inlined.u.rbyd,
|
||||||
lfs_min32(
|
lfs_min32(
|
||||||
pos,
|
pos,
|
||||||
@@ -9324,11 +9242,12 @@ static int lfsr_file_carveinlined(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
}
|
}
|
||||||
LFS_ASSERT(left_tag == LFSR_TAG_SHRUB(INLINED));
|
LFS_ASSERT(left_tag == LFSR_TAG_SHRUB(INLINED));
|
||||||
LFS_ASSERT(lfsr_data_size(&left_data) <= left_weight);
|
LFS_ASSERT(lfsr_data_size(&left_data) <= left_weight);
|
||||||
|
}
|
||||||
|
|
||||||
// this can be negative!
|
// this can be negative!
|
||||||
left_overlap = (left_rid+1) - pos;
|
left_overlap = (left_rid+1) - pos;
|
||||||
LFS_ASSERT(left_overlap >= 0
|
LFS_ASSERT(left_overlap >= 0
|
||||||
|| (lfs_off_t)file->inlined.u.rbyd.weight < pos);
|
|| lfsr_file_inlinedsize(file) < pos);
|
||||||
|
|
||||||
// can we coalesce left data?
|
// can we coalesce left data?
|
||||||
if (left_rid-(left_weight-1) + lfsr_data_size(&left_data)
|
if (left_rid-(left_weight-1) + lfsr_data_size(&left_data)
|
||||||
@@ -9346,6 +9265,18 @@ static int lfsr_file_carveinlined(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
pos = left_rid-(left_weight-1);
|
pos = left_rid-(left_weight-1);
|
||||||
left_overlap = 0;
|
left_overlap = 0;
|
||||||
|
|
||||||
|
// need to append left data? this can happend if we're
|
||||||
|
// transitioning from a sprout to a shrub
|
||||||
|
} else if (!lfsr_file_hasshrub(file)) {
|
||||||
|
*attrs_++ = LFSR_ATTR(left_rid-(left_weight-1),
|
||||||
|
SHRUB(INLINED), +left_weight - left_overlap, DISK(
|
||||||
|
left_data.u.disk.block,
|
||||||
|
left_data.u.disk.off,
|
||||||
|
left_weight - lfs_smax32(left_overlap, 0)));
|
||||||
|
|
||||||
|
estimate += LFSR_ATTR_ESTIMATE
|
||||||
|
+ (left_weight - lfs_smax32(left_overlap, 0));
|
||||||
|
|
||||||
// need to carve out left data?
|
// need to carve out left data?
|
||||||
} else if (left_rid-(left_weight-1) + lfsr_data_size(&left_data)
|
} else if (left_rid-(left_weight-1) + lfsr_data_size(&left_data)
|
||||||
> pos) {
|
> pos) {
|
||||||
@@ -9360,7 +9291,7 @@ static int lfsr_file_carveinlined(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
+ lfsr_data_size(&left_data)
|
+ lfsr_data_size(&left_data)
|
||||||
- pos;
|
- pos;
|
||||||
|
|
||||||
// adjust left sibling with a grow attr, this may create a hole
|
// adjust left sibling with a grow attr, avoiding a data copy
|
||||||
} else if (left_overlap != 0) {
|
} else if (left_overlap != 0) {
|
||||||
*attrs_++ = LFSR_ATTR(left_rid,
|
*attrs_++ = LFSR_ATTR(left_rid,
|
||||||
SHRUB(GROW), -left_overlap, NULL);
|
SHRUB(GROW), -left_overlap, NULL);
|
||||||
@@ -9368,11 +9299,16 @@ static int lfsr_file_carveinlined(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// has right sibling?
|
// has right sibling?
|
||||||
if (pos + weight < (lfs_off_t)file->inlined.u.rbyd.weight) {
|
if (pos + weight < lfsr_file_inlinedsize(file)) {
|
||||||
lfsr_srid_t right_rid;
|
lfsr_srid_t right_rid;
|
||||||
lfsr_tag_t right_tag;
|
|
||||||
lfsr_rid_t right_weight;
|
lfsr_rid_t right_weight;
|
||||||
lfsr_data_t right_data;
|
lfsr_data_t right_data;
|
||||||
|
if (!lfsr_file_hasshrub(file)) {
|
||||||
|
right_rid = lfsr_data_size(&file->inlined.u.data)-1;
|
||||||
|
right_weight = lfsr_data_size(&file->inlined.u.data);
|
||||||
|
right_data = file->inlined.u.data;
|
||||||
|
} else {
|
||||||
|
lfsr_tag_t right_tag;
|
||||||
int err = lfsr_rbyd_lookupnext(lfs, &file->inlined.u.rbyd,
|
int err = lfsr_rbyd_lookupnext(lfs, &file->inlined.u.rbyd,
|
||||||
pos + weight, 0,
|
pos + weight, 0,
|
||||||
&right_rid, &right_tag, &right_weight, &right_data);
|
&right_rid, &right_tag, &right_weight, &right_data);
|
||||||
@@ -9382,6 +9318,7 @@ static int lfsr_file_carveinlined(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
}
|
}
|
||||||
LFS_ASSERT(right_tag == LFSR_TAG_SHRUB(INLINED));
|
LFS_ASSERT(right_tag == LFSR_TAG_SHRUB(INLINED));
|
||||||
LFS_ASSERT(lfsr_data_size(&right_data) <= right_weight);
|
LFS_ASSERT(lfsr_data_size(&right_data) <= right_weight);
|
||||||
|
}
|
||||||
|
|
||||||
right_overlap = pos + weight
|
right_overlap = pos + weight
|
||||||
- (right_rid-(right_weight-1));
|
- (right_rid-(right_weight-1));
|
||||||
@@ -9406,10 +9343,12 @@ static int lfsr_file_carveinlined(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
weight += right_weight - right_overlap;
|
weight += right_weight - right_overlap;
|
||||||
right_overlap = 0;
|
right_overlap = 0;
|
||||||
|
|
||||||
// is right sibling the same as left sibling? need to
|
// need to append right data? this can happen if we're
|
||||||
// split right data and handle this a bit differently
|
// transitioning from sprout to shrub, or left and right sibling
|
||||||
} else if (right_overlap > (lfs_soff_t)weight) {
|
// are the same
|
||||||
*attrs_++ = LFSR_ATTR(right_rid+1 - left_overlap,
|
} else if (!lfsr_file_hasshrub(file)
|
||||||
|
|| right_overlap > (lfs_soff_t)weight) {
|
||||||
|
*attrs_++ = LFSR_ATTR(pos - left_overlap,
|
||||||
SHRUB(INLINED), +right_weight - right_overlap,
|
SHRUB(INLINED), +right_weight - right_overlap,
|
||||||
DISK(
|
DISK(
|
||||||
right_data.u.disk.block,
|
right_data.u.disk.block,
|
||||||
@@ -9439,15 +9378,10 @@ static int lfsr_file_carveinlined(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// remove any data we're overwriting, accounting for sibling changes
|
// remove any data we're overwriting, accounting for sibling changes
|
||||||
// lfs_soff_t rm = lfs_smin32(
|
if (lfsr_file_hasshrub(file)) {
|
||||||
// weight - left_overlap - right_overlap,
|
|
||||||
// file->inlined.u.rbyd.weight
|
|
||||||
// - lfs_min32(
|
|
||||||
// pos + left_overlap,
|
|
||||||
// file->inlined.u.rbyd.weight));
|
|
||||||
lfs_soff_t rm = lfs_smin32(
|
lfs_soff_t rm = lfs_smin32(
|
||||||
weight,
|
weight,
|
||||||
file->inlined.u.rbyd.weight - pos)
|
lfsr_file_inlinedsize(file) - pos)
|
||||||
- left_overlap
|
- left_overlap
|
||||||
- right_overlap;
|
- right_overlap;
|
||||||
if (rm > 0) {
|
if (rm > 0) {
|
||||||
@@ -9464,6 +9398,7 @@ static int lfsr_file_carveinlined(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
}
|
}
|
||||||
estimate -= rm_estimate;
|
estimate -= rm_estimate;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// append our buffer
|
// append our buffer
|
||||||
if (weight + delta > 0) {
|
if (weight + delta > 0) {
|
||||||
@@ -9473,7 +9408,6 @@ static int lfsr_file_carveinlined(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
estimate += LFSR_ATTR_ESTIMATE
|
estimate += LFSR_ATTR_ESTIMATE
|
||||||
+ lfsr_data_size(&data);
|
+ lfsr_data_size(&data);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// TODO can this happen? should we even have special handling here?
|
// TODO can this happen? should we even have special handling here?
|
||||||
// this is a noop?
|
// this is a noop?
|
||||||
|
|||||||
Reference in New Issue
Block a user