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 first_segment_of_write > last_segment_of_current: # 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. fetch_first_segment = False elif (first_segment_of_write == last_segment_of_current) and \ (offset == (first_segment_of_write * segsize)) and \ ((offset + length) >= filesize): # If this segment is the last segment of the current file and we're # overwriting all the bytes in this segment, then no need to fetch # it. fetch_first_segment = False elif (offset == (first_segment_of_write * segsize)) and \ ((offset + length) >= ((first_segment_of_write+1) * segsize)): # If we are overwriting the entire segment, then no need to fetch the # current version. fetch_first_segment = False # If the last segment is also the first segment, then we're done. 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 last_segment_of_write > last_segment_of_current: # 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. fetch_last_segment = False elif last_segment_of_write == last_segment_of_current: # If this is the last segment of the current file and we are # overwriting all of the bytes in this segment, then we don't need to fetch it. if offset + length >= filesize: 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)