Skip to content

Commit

Permalink
Merge pull request #61 from Gottox/feature/specific-skip
Browse files Browse the repository at this point in the history
Implement _skip for data iterators.
  • Loading branch information
Gottox committed Aug 22, 2023
2 parents 835312e + aa54481 commit ca9ea77
Show file tree
Hide file tree
Showing 12 changed files with 275 additions and 56 deletions.
18 changes: 18 additions & 0 deletions include/sqsh_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,24 @@ sqsh_file_iterator_new(const struct SqshFile *file, int *err);
SQSH_NO_UNUSED bool sqsh_file_iterator_next(
struct SqshFileIterator *iterator, size_t desired_size, int *err);

/**
* @memberof SqshFileIterator
* @brief Skips blocks until the block containing the offset is reached.
* Note that calling this function will invalidate the data pointer returned by
* sqsh_file_iterator_data().
*
* @param[in,out] iterator The file iterator to skip data in.
* @param[in] offset The offset that is contained in the block to skip
* to.
* @param[in] desired_size The desired size of the data to read. May be more or
* less than the actual size of the data read.
*
* @return 0 on success, less than 0 on error.
*/
SQSH_NO_UNUSED int sqsh_file_iterator_skip(
struct SqshFileIterator *iterator, sqsh_index_t *offset,
size_t desired_size);

/**
* @brief Gets a pointer to the current data in the file iterator.
* @memberof SqshFileIterator
Expand Down
17 changes: 16 additions & 1 deletion include/sqsh_mapper_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ struct SqshMapIterator {
/**
* @privatesection
*/
sqsh_index_t index;
sqsh_index_t next_index;
sqsh_index_t segment_count;
struct SqshMapManager *map_manager;
const struct SqshMapSlice *mapping;
Expand Down Expand Up @@ -404,6 +404,21 @@ SQSH_NO_EXPORT SQSH_NO_UNUSED int sqsh__map_iterator_init(
SQSH_NO_EXPORT SQSH_NO_UNUSED bool
sqsh__map_iterator_next(struct SqshMapIterator *iterator, int *err);

/**
* @memberof SqshMapIterator
* @brief Skips blocks until the block containing the offset is reached.
* Note that calling this function will invalidate the data pointer returned by
* sqsh_map_iterator_data().
*
* @param[in,out] iterator The map iterator to skip data in.
* @param[in] offset The offset that is contained in the block to
* skip to.
*
* @return 0 on success, less than 0 on error.
*/
SQSH_NO_EXPORT SQSH_NO_UNUSED int
sqsh__map_iterator_skip(struct SqshMapIterator *iterator, sqsh_index_t *offset);

/**
* @internal
* @memberof SqshMapIterator
Expand Down
16 changes: 16 additions & 0 deletions include/sqsh_metablock_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ struct SqshMetablockIterator {
struct SqshMapReader reader;
struct SqshExtractManager *compression_manager;
struct SqshExtractView extract_view;
bool is_compressed;
uint16_t outer_size;
uint16_t inner_size;
const uint8_t *data;
Expand Down Expand Up @@ -92,6 +93,21 @@ SQSH_NO_EXPORT SQSH_NO_UNUSED int sqsh__metablock_iterator_init(
SQSH_NO_EXPORT bool
sqsh__metablock_iterator_next(struct SqshMetablockIterator *iterator, int *err);

/**
* @memberof SqshMetablockIterator
* @brief Skips blocks until the block containing the offset is reached.
* Note that calling this function will invalidate the data pointer returned by
* sqsh_metablock_iterator_data().
*
* @param[in,out] iterator The metablock iterator to skip data in.
* @param[in] offset The offset that is contained in the block to
* skip to.
*
* @return 0 on success, less than 0 on error.
*/
SQSH_NO_UNUSED int sqsh__metablock_iterator_skip(
struct SqshMetablockIterator *iterator, sqsh_index_t *offset);

/**
* @internal
* @memberof SqshMetablockIterator
Expand Down
1 change: 1 addition & 0 deletions include/sqsh_reader_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ extern "C" {

struct SqshReaderIteratorImpl {
bool (*next)(void *iterator, size_t desired_size, int *err);
int (*skip)(void *iterator, sqsh_index_t *offset, size_t desired_size);
const uint8_t *(*data)(const void *iterator);
size_t (*size)(const void *iterator);
};
Expand Down
52 changes: 52 additions & 0 deletions lib/file/file_iterator.c
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,58 @@ sqsh_file_iterator_next(
return has_next;
}

int
sqsh_file_iterator_skip(
struct SqshFileIterator *iterator, sqsh_index_t *offset,
size_t desired_size) {
int rv = 0;
const size_t block_size = iterator->block_size;
const sqsh_index_t skip_index = *offset / block_size;
*offset = *offset % block_size;

if (skip_index == 0 && iterator->block_index != 0) {
goto out;
}

sqsh_index_t reader_forward = 0;
sqsh_index_t block_index = iterator->block_index;
for (sqsh_index_t i = 0; i < skip_index; i++) {
reader_forward += sqsh_file_block_size(iterator->file, block_index);
block_index += 1;
}
rv = sqsh__map_reader_advance(&iterator->map_reader, reader_forward, 0);
if (rv < 0) {
goto out;
}
iterator->sparse_size = 0;
iterator->block_index = block_index;

/* In general we will get directly the block containing the offset, but if
* the offset points to a block with sparse sections, we iterate over them
* until we reach the desired offset.
*
* TODO: We could analyze iterator->sparse_size and directly skip to the
* desired block.
*/
size_t current_size = sqsh_file_iterator_size(iterator);
while (current_size <= *offset) {
*offset -= current_size;
bool has_next = sqsh_file_iterator_next(iterator, desired_size, &rv);
if (rv < 0) {
goto out;
} else if (!has_next) {
rv = -SQSH_ERROR_OUT_OF_BOUNDS;
goto out;
}
current_size = sqsh_file_iterator_size(iterator);
}

rv = 0;

out:
return rv;
}

const uint8_t *
sqsh_file_iterator_data(const struct SqshFileIterator *iterator) {
return iterator->data;
Expand Down
5 changes: 5 additions & 0 deletions lib/file/file_reader.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ static bool
file_iterator_next(void *iterator, size_t desired_size, int *err) {
return sqsh_file_iterator_next(iterator, desired_size, err);
}
static int
file_iterator_skip(void *iterator, sqsh_index_t *offset, size_t desired_size) {
return sqsh_file_iterator_skip(iterator, offset, desired_size);
}
static const uint8_t *
file_iterator_data(const void *iterator) {
return sqsh_file_iterator_data(iterator);
Expand All @@ -54,6 +58,7 @@ file_iterator_size(const void *iterator) {

static const struct SqshReaderIteratorImpl file_reader_impl = {
.next = file_iterator_next,
.skip = file_iterator_skip,
.data = file_iterator_data,
.size = file_iterator_size,
};
Expand Down
55 changes: 46 additions & 9 deletions lib/mapper/map_iterator.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ sqsh__map_iterator_init(
}

iterator->map_manager = manager;
iterator->index = address_to_index(iterator, start_address);
iterator->next_index = address_to_index(iterator, start_address);
iterator->mapping = NULL;
iterator->data = NULL;
iterator->size = 0;
Expand All @@ -72,17 +72,52 @@ sqsh__map_iterator_init(
return 0;
}

#include <stdio.h>
int
sqsh__map_iterator_skip(
struct SqshMapIterator *iterator, sqsh_index_t *offset) {
int rv = 0;
sqsh_index_t index = iterator->next_index;
size_t block_size = sqsh__map_manager_block_size(iterator->map_manager);

size_t current_size = sqsh__map_iterator_size(iterator);
if (*offset < current_size) {
goto out;
}

index = iterator->next_index + (*offset / block_size);
if (current_size > 0) {
/* If there is a segment currently mapped, we need don't need to skip
* that one, hence reduce the index by one.
*/
index--;
}

iterator->next_index = index;
bool has_next = sqsh__map_iterator_next(iterator, &rv);
if (rv < 0) {
goto out;
} else if (has_next == false) {
rv = -SQSH_ERROR_OUT_OF_BOUNDS;
goto out;
}

*offset %= block_size;
if (*offset > sqsh__map_iterator_size(iterator)) {
rv = -SQSH_ERROR_OUT_OF_BOUNDS;
goto out;
}
rv = 0;
out:
return rv;
}

bool
sqsh__map_iterator_next(struct SqshMapIterator *iterator, int *err) {
int rv;
bool has_next = false;

iterator->index++;
if (iterator->mapping == NULL) {
iterator->index -= 1;
}

if (iterator->index >= iterator->segment_count) {
if (iterator->next_index >= iterator->segment_count) {
rv = 0;
iterator->data = NULL;
iterator->size = 0;
Expand All @@ -91,14 +126,16 @@ sqsh__map_iterator_next(struct SqshMapIterator *iterator, int *err) {

sqsh__map_manager_release(iterator->map_manager, iterator->mapping);
rv = sqsh__map_manager_get(
iterator->map_manager, iterator->index, &iterator->mapping);
iterator->map_manager, iterator->next_index, &iterator->mapping);
if (rv < 0) {
goto out;
}

iterator->size = sqsh__map_slice_size(iterator->mapping);
iterator->data = sqsh__map_slice_data(iterator->mapping);
has_next = iterator->size > 0;

iterator->next_index++;
out:
if (err != NULL) {
*err = rv;
Expand All @@ -118,7 +155,7 @@ sqsh__map_iterator_block_size(const struct SqshMapIterator *iterator) {

sqsh_index_t
sqsh__map_iterator_address(const struct SqshMapIterator *iterator) {
return index_to_address(iterator, iterator->index);
return index_to_address(iterator, iterator->next_index);
}

size_t
Expand Down
6 changes: 6 additions & 0 deletions lib/mapper/map_reader.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ map_iterator_next(void *iterator, size_t desired_size, int *err) {
(void)desired_size;
return sqsh__map_iterator_next(iterator, err);
}
static int
map_iterator_skip(void *iterator, sqsh_index_t *offset, size_t desired_size) {
(void)desired_size;
return sqsh__map_iterator_skip(iterator, offset);
}
static const uint8_t *
map_iterator_data(const void *iterator) {
return sqsh__map_iterator_data(iterator);
Expand All @@ -52,6 +57,7 @@ map_iterator_size(const void *iterator) {

static const struct SqshReaderIteratorImpl map_reader_impl = {
.next = map_iterator_next,
.skip = map_iterator_skip,
.data = map_iterator_data,
.size = map_iterator_size,
};
Expand Down
Loading

0 comments on commit ca9ea77

Please sign in to comment.