def choose_segs(filesize, segsize, offset, length): """ What segments do you need to write to, and to read from, given an filesize-byte file, split into segsize-byte segments, the last one of which could be fewer than segsize bytes, and an offset and non-zero length that needs to be written? Those are the inputs to the algorithm. The output is: first_segment (int), fetch_first_segment (boolean), last_segment (int), fetch_last_segment (boolean). The meaning of "fetch" is: "We have to fetch the current value of this segment in order to compute what the new value of the segment should be.". That is true whenever the write is writing part of the segment and leaving other bytes within the segment with their current value. The only constraints on the output are that last_segment >= first_segment, and that if last_segment == first_segment then fetch_last_segment == first_first_segment. """ precondition(filesize >= 0, filesize) precondition(segsize >= 1, segsize) precondition(offset >= 0, offset) precondition(length >= 1, length) first_segment_of_write = offset // segsize last_byte_of_write = offset + length - 1 last_segment_of_write = last_byte_of_write // segsize num_segs_in_current = div_ceil(filesize, segsize) last_segment_of_current = num_segs_in_current - 1 # Now let's figure out if we need to fetch the first segment. Initialize # fetch_last_segment to True and then check whether we don't actually # need to fetch it. fetch_first_segment = True # If it is a segment that doesn't currently exist at all (it is past the # end) then we don't need to fetch it. if first_segment_of_write > last_segment_of_current: fetch_first_segment = False else: # If we are overwriting the entire segment, then no need to fetch the # current version. if (offset % segsize == 0) and ( (last_segment_of_write > first_segment_of_write) or ((offset + length) % segsize == 0) ): fetch_first_segment = False if last_segment_of_write == first_segment_of_write: return (first_segment, fetch_first_segment, first_segment, fetch_first_segment) # Now let's figure out if we need to fetch the last segment. fetch_last_segment = True # If it is a segment that doesn't currently exist at all (it is past the # end) then we don't need to fetch it. if last_segment_of_write > last_segment_of_current: fetch_last_segment = False else: # If we are overwriting the entire segment, then no need to fetch the # current version. if (offset + length) % segsize == 0: fetch_last_segment = False return (first_segment, fetch_first_segment, last_segment, fetch_last_segment)