-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
vcs-svn: learn to maintain a sliding view of a file
Each section of a Subversion-format delta only requires examining (and keeping in random-access memory) a small portion of the preimage. At any moment, this portion starts at a certain file offset and has a well-defined length, and as the delta is applied, the portion advances from the beginning to the end of the preimage. Add a move_window function to keep track of this view into the preimage. You can use it like this: buffer_init(f, NULL); struct sliding_view window = SLIDING_VIEW_INIT(f); move_window(&window, 3, 7); /* (1) */ move_window(&window, 5, 5); /* (2) */ move_window(&window, 12, 2); /* (3) */ strbuf_release(&window.buf); buffer_deinit(f); The data structure is called sliding_view instead of _window to prevent confusion with svndiff0 Windows. In this example, (1) reads 10 bytes and discards the first 3; (2) discards the first 2, which are not needed any more; and (3) skips 2 bytes and reads 2 new bytes to work with. When move_window returns, the file position indicator is at position window->off + window->width and the data from positions window->off to the current file position are stored in window->buf. This function performs only sequential access from the input file and never seeks, so it can be safely used on pipes and sockets. On end-of-file, move_window silently reads less than the caller requested. On other errors, it prints a message and returns -1. Helped-by: David Barr <david.barr@cordelta.com> Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
- Loading branch information
Jonathan Nieder
committed
Mar 28, 2011
1 parent
3371f9b
commit 9d2f5dd
Showing
4 changed files
with
98 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
/* | ||
* Licensed under a two-clause BSD-style license. | ||
* See LICENSE for details. | ||
*/ | ||
|
||
#include "git-compat-util.h" | ||
#include "sliding_window.h" | ||
#include "line_buffer.h" | ||
#include "strbuf.h" | ||
|
||
static int input_error(struct line_buffer *file) | ||
{ | ||
if (!buffer_ferror(file)) | ||
return error("delta preimage ends early"); | ||
return error("cannot read delta preimage: %s", strerror(errno)); | ||
} | ||
|
||
static int skip_or_whine(struct line_buffer *file, off_t gap) | ||
{ | ||
if (buffer_skip_bytes(file, gap) != gap) | ||
return input_error(file); | ||
return 0; | ||
} | ||
|
||
static int read_to_fill_or_whine(struct line_buffer *file, | ||
struct strbuf *buf, size_t width) | ||
{ | ||
buffer_read_binary(file, buf, width - buf->len); | ||
if (buf->len != width) | ||
return input_error(file); | ||
return 0; | ||
} | ||
|
||
static int check_overflow(off_t a, size_t b) | ||
{ | ||
if (b > maximum_signed_value_of_type(off_t)) | ||
return error("unrepresentable length in delta: " | ||
"%"PRIuMAX" > OFF_MAX", (uintmax_t) b); | ||
if (signed_add_overflows(a, (off_t) b)) | ||
return error("unrepresentable offset in delta: " | ||
"%"PRIuMAX" + %"PRIuMAX" > OFF_MAX", | ||
(uintmax_t) a, (uintmax_t) b); | ||
return 0; | ||
} | ||
|
||
int move_window(struct sliding_view *view, off_t off, size_t width) | ||
{ | ||
off_t file_offset; | ||
assert(view); | ||
assert(view->width <= view->buf.len); | ||
assert(!check_overflow(view->off, view->buf.len)); | ||
|
||
if (check_overflow(off, width)) | ||
return -1; | ||
if (off < view->off || off + width < view->off + view->width) | ||
return error("invalid delta: window slides left"); | ||
|
||
file_offset = view->off + view->buf.len; | ||
if (off < file_offset) { | ||
/* Move the overlapping region into place. */ | ||
strbuf_remove(&view->buf, 0, off - view->off); | ||
} else { | ||
/* Seek ahead to skip the gap. */ | ||
if (skip_or_whine(view->file, off - file_offset)) | ||
return -1; | ||
strbuf_setlen(&view->buf, 0); | ||
} | ||
|
||
if (view->buf.len > width) | ||
; /* Already read. */ | ||
else if (read_to_fill_or_whine(view->file, &view->buf, width)) | ||
return -1; | ||
|
||
view->off = off; | ||
view->width = width; | ||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
#ifndef SLIDING_WINDOW_H_ | ||
#define SLIDING_WINDOW_H_ | ||
|
||
#include "strbuf.h" | ||
|
||
struct sliding_view { | ||
struct line_buffer *file; | ||
off_t off; | ||
size_t width; | ||
struct strbuf buf; | ||
}; | ||
|
||
#define SLIDING_VIEW_INIT(input) { (input), 0, 0, STRBUF_INIT } | ||
|
||
extern int move_window(struct sliding_view *view, off_t off, size_t width); | ||
|
||
#endif |