/****************************************************************************
**  SIONLIB     http://www.fz-juelich.de/jsc/sionlib                       **
*****************************************************************************
**  Copyright (c) 2018-2019                                                **
**  Forschungszentrum Juelich, Juelich Supercomputing Centre               **
**                                                                         **
**  See the file COPYRIGHT in the package base directory for details       **
****************************************************************************/

/// \cond sion_internal
/// \file
/// \brief Positioning in physical and logical files
///
/// This file defines several types and associated functions concerned with positioning in the physical and logical files of a SIONlib file container.
///
/// A file is a sequence of positions addressable by integer numbers `[0, 1, ...]`.
/// A SIONlib container can store an arbitrary number of logical files inside a single physical file.
/// A logical file occupies a sequence of chunks inside the address space of the containing physical file.
/// The type \ref _sion_chunk_sequence models such a sequence of chunks.
/// A chunk -- or a part of a chunk -- is a range of consecutive positions in the physical file, this is modeled by the type \ref _sion_range.
/// Accessing data in logical files (reading or writing) visits a sequence of ranges, this is modeled by the range iterator types such as \ref _sion_range_iterator and \ref _sion_partitioned_range_iterator.

#ifndef SION_INTERNAL_POSITIONING_H
#define SION_INTERNAL_POSITIONING_H

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

#include "sion_filedesc.h"

/// \brief A range of consecutive positions in a file
///
/// A range `range(start, length)` includes the positions `[start, start + 1, ..., start + length - 1]`.
typedef struct {
  int64_t start; ///< the first position included in the range
  int64_t length; ///< the number of positions included in the range
} _sion_range;

/// \brief A sequence of chunks
///
/// This describes the sequence of chunks of a physical file that belong to a particular logical file.
/// A chunk sequence is specified by a `start` position (the position in a physical file where the start of the first chunk in a sequence is located), the size of the chunks and the stride between the start positions of two consecutive chunks.
///
/// \note The sequence as modeled by this type is open ended, i.e. there is a first chunk, but no last chunk.
/// This describes all chunks in a physical file that could be occupied by a logical file.
///
/// A chunk sequence `chunk_sequence(start, stride, chunksize)` includes the positions `[start, start + 1, ..., start + chunksize - 1, start + stride, start + stride + 1, ..., start + stride + chunksize - 1, start + 2 * stride, ...]`, i.e. it is the union of all ranges `range(start + i * stride, chunksize)` for `i = 0, 1, ...`.
typedef struct {
  int64_t start; ///< the position at which the first chunk in the sequence starts
  int64_t stride; ///< the distance between the start positions of two consecutive chunks in the sequence
  int64_t chunksize; ///< the size (number of positions) of a chunk in the sequence
} _sion_chunk_sequence;

/// \brief A limited sequence of chunks with individual sizes
///
/// This describes the sequence of chunks in a physical file produced by a previous version of SIONlib that belong to a particular
/// logical file.
/// Similar to _sion_chunk_sequence, but differs in the following two aspects:
/// - there is only a limited number of chunks (since these files can only be read and no chunks can be added),
/// - all chunks can have different sizes (limited by a maximum chunk size).
typedef struct {
  int64_t start; ///< the position at which the first chunk in the sequence starts
  int64_t stride; ///< the distance between the start positions of two consecutive chunks in the sequence
  size_t n_chunks; ///< the number of chunks in this sequence
  const int64_t *chunk_sizes; ///< the individual sizes of all chunks
  int64_t ubound; ///< one past last physical position in sequence, memoized for optimized out-of-bounds checks
} _sion_limited_chunk_sequence;

/// \brief Determines the kind of a range yielded from a range iterator
///
/// A range yielded from an iterator may either be the remainder of a chunk that the file pointer is currently resting in or a part
/// of a chunk that the file pointer has to be moved to first. This detail of traversing the ranges of a physical file that belong
/// to a logical file is exposed via this return type of iterator `next` functions primarily to allow consumers of this API to
/// take appropriate actions in each case (e.g. applying file system hints).
///
/// \note The value of `_SION_EXHAUSTED` is explicitly defined as `0` to make it falsy. This way, the return value of range
/// iterator `next` functions can be used in the condition clause of loop constructs.
typedef enum {
  /// \brief the iterator has been exhausted, there are no more ranges to yield
  _SION_EXHAUSTED = 0,
  /// \brief the range is part of a chunk that the file pointer has to be moved to
  _SION_NEXT,
  /// \brief the range is part of a chunk that the file pointer is currently resting in
  _SION_REMAINDER,
} _sion_range_kind;

/// \brief An iterator over a sequence of ranges that contain a desired number of positions starting from a given position in a physical file
///
/// Accessing a sequence of consecutive positions in a logical file of a SIONlib file container (e.g. reading or writing) means accessing all positions in a sequence of ranges in the physical file.
/// This iterator yields a sequence of ranges that in sum contain a desired number of positions (e.g. the amount to read or write) starting from a position in the physical file (e.g. the current position of the file pointer).
///
/// If the starting position lies within a chunk in the sequence, the first range returned is (the remainder of) that chunk.
/// Otherwise the next chunk after the start position is the first range returned.
/// All subsequent ranges are entire chunks with the exception of the last one which might be shorter than a chunk.
typedef struct {
  _sion_chunk_sequence sequence; ///< the underlying sequence of chunks describing the logical file
  int64_t position; ///< the first position in the physical file
  int64_t remaining; ///< the remaining desired number of positions
} _sion_range_iterator;

/// \brief An iterator over a sequence of partitioned ranges that contain a desired number of positions starting from a given position in a physical file
///
/// Wraps \ref _sion_range_iterator and splits every range it yields into sub-ranges no larger than the partition size.
/// This is useful for collective data access, where data is transferred in blocks that might be smaller than the chunks of a logical file.
typedef struct {
  _sion_range_iterator inner; ///< the underlying range iterator
  _sion_range current; ///< a range from the underlying iterator that is currently being split into `partition` sized portions
  int64_t partition; ///< the maximum desired size of ranges yielded by this iterator
} _sion_partitioned_range_iterator;

/// \brief An iterator over a sequence of ranges with individual size limits
///
/// This iterator returns a sequence of ranges that encompass chunks from a \ref _sion_limited_chunk_sequence similar to \ref _sion_range_iterator.
/// However, the size of each individual chunk is determined from an additional sequence of chunk sizes.
///
/// Earlier versions of SIONlib produced files with chunks that had individual filling levels.
/// To ensure backward compatibility with these older files, this iterator is used for reading.
typedef struct {
  _sion_limited_chunk_sequence sequence; ///< the underlying sequence of chunks describing the logical file
  int64_t position; ///< the first position in the physical file
  int64_t remaining; ///< the remaining desired number of positions
} _sion_limited_range_iterator;

/// \brief An iterator over a sequence of partitioned ranges with individual size limits
///
/// Wraps \ref _sion_limited_range_iterator and splits every range it yields into sub-ranges no larger than the partition size.
/// This is useful for collective data access, where data is transferred in blocks that might be smaller than the chunks of a logical file.
typedef struct {
  _sion_limited_range_iterator inner; ///< the underlying range iterator
  _sion_range current; ///< a range from the underlying iterator that is currently being split into `partition` sized portions
  int64_t partition; ///< the maximum desired size of ranges yielded by this iterator
} _sion_partitioned_limited_range_iterator;

/// \brief split a prefix off of a range
///
/// This splits a prefix of up to `length` positions (or less if the range is shorter than `length`) from the begining of a range.
/// The prefix range is returned, the original range is modified to contain only the remaining suffix (possibly empty).
///
/// \param[in,out] range the range to split the prefix from
/// \param[in] length the desired length of the prefix to split off
///
/// \returns a prefix that contains up to `length` positions
_sion_range _sion_range_split_off_prefix(_sion_range *range, int64_t length);

/// \brief clamp the length of a range
///
/// If necessary, shortens the range by decreasing its length to at most the desired value `length`.
///
/// \param[in,out] range the range to clamp
/// \param[in] length the desired length
void _sion_range_clamp(_sion_range *range, int64_t length);

/// \brief Copy a range into a spec
void _sion_range_into_spec(_sion_range range, int64_t *spec);

/// \brief construct a chunk sequence from basic parts
///
/// A sequence of chunks is fully specified by the `start` position of the first chunk, the size of all chunks and the `stride` between consecutive chunks.
///
/// \param[in] start the position at which the first chunk in the sequence starts
/// \param[in] stride the distance between the start positions of two consecutive chunks in the sequence
/// \param[in] chunksize the size (number of positions) of a chunk in the sequence
///
/// \returns the newly constructed sequence
_sion_chunk_sequence _sion_chunk_sequence_from_parts(int64_t start, int64_t stride, int64_t chunksize);

/// \brief construct a chunk sequence for an open file
///
/// Exctracts the information necessary to specify the chunk sequence from an open file (specifically, the currently open logical file, i.e. `fd->startpos`, `fd->globalskip`, `fd->chunksize`).
///
/// \param[in] fd the file descriptor to exctract the information from
///
/// \returns the newly constructed sequence
_sion_chunk_sequence _sion_chunk_sequence_from_filedesc(const _sion_filedesc *fd);

/// \brief tests whether a physical positions lies outside a chunk sequence
///
/// This always returns `false`, since positions that lie before the start of the range are forbidden.
///
/// \param[in] sequence the chunk sequence
/// \param[in] physical_position the physical position to test
///
/// \returns `false`
bool _sion_chunk_sequence_position_oob(const _sion_chunk_sequence *sequence, int64_t physical_position);

/// \brief translate a logical address to a physical address
///
/// Maps an address in a logical file to an address in the physical file it is contained in using the parameters of the given chunk
/// sequence.
///
/// \param[in] sequence specifies the sequence of chunks in the physical file that belong to the logical file to map into
/// \param[in] logical_position position in the logical file that shall be translated into a position in the physical file
///
/// \returns a position in the physical file that corresponds to `logical_position`
int64_t _sion_chunk_sequence_translate_l2p(const _sion_chunk_sequence *sequence, int64_t logical_position);

/// \brief translate a logical address to a chunk number
///
/// Maps an address in a logical file to a chunk in the sequence of chunks.
///
/// \param[in] sequence specifies the sequence of chunks in the physical file that belong to the logical file to map into
/// \param[in] logical_position position in the logical file that shall be translated into a chunk number
///
/// \returns the number of the chunk that the logical psoition lies in
int32_t _sion_chunk_sequence_translate_l2n(const _sion_chunk_sequence *sequence, int64_t logical_position);

/// \brief translate physical address to logical address
///
/// Maps an address in a physical file to an address in a logical file contained therein using the parameters of the given chunk
/// sequence.
/// Physical addresses that lie between two chunks in the sequence are mapped to the first address in the next chunk.
///
/// \param[in] sequence specifies the sequence of chunks in the physical file that belong to the logical file to map into
/// \param[in] physical_position position in the physical file that shall be translated into a position in the logical file
///
/// \returns a position in the logical file that corresponds to `physical_position`
int64_t _sion_chunk_sequence_translate_p2l(const _sion_chunk_sequence *sequence, int64_t physical_position);

/// \brief translate physical address to a chunk number
///
/// Maps an address in a physical file to the number of the chunk it lies in, or if it lies between two chunks in the sequence it
/// is mapped to the number of the next chunk.
///
/// \param[in] sequence specifies the sequence of chunks in the physical file that belong to the logical file to map into
/// \param[in] physical_position position in the physical file that shall be translated into a chunk number
///
/// \returns a chunk number that corresponds to `physical_position`
int32_t _sion_chunk_sequence_translate_p2n(const _sion_chunk_sequence *sequence, int64_t physical_position);

/// \brief looks up a chunk in a sequence by its chunk number
///
/// \param[in] sequence the sequence in which to look up the chunk
/// \param[in] chunk_number the number of the chunk to look up
///
/// \returns a range encompassing the chunk of the desired number `range(sequence->start + chunk_number * sequence->stride, sequence->chunk_size)`
_sion_range _sion_chunk_sequence_chunk_from_number(const _sion_chunk_sequence *sequence, int32_t chunk_number);

/// \brief looks up a chunk (or its remainder) in a sequence by physical position
///
/// Maps the physical position to a chunk in the sequence. If the physical position lies between two chunks, the entire next chunk
/// is returned, otherwise the remainder of the chunk the position lies in, beyond the position.
///
/// \param[in] sequence the sequence in which to look up the chunk
/// \param[in] physical_position the physical position at which to look up the chunk
///
/// \returns a range encompasing a chunk or the remainder of a chunk corresponding to the physical position
_sion_range _sion_chunk_sequence_chunk_from_physical_position(const _sion_chunk_sequence *sequence, int64_t physical_position);

/// \brief looks up a chunk (or its remainder) in a sequence by logical position
///
/// Maps the logical position to a chunk in the sequence, and returns the remainder of the chunk the position lies in,
/// beyond the position.
///
/// \param[in] sequence the sequence in which to look up the chunk
/// \param[in] logical_position the logical position at which to look up the chunk
///
/// \returns a range encompasing a chunk or the remainder of a chunk corresponding to the logical position
_sion_range _sion_chunk_sequence_chunk_from_logical_position(const _sion_chunk_sequence *sequence, int64_t logical_position);

/// \brief construct a limited chunk sequence from basic parts
///
/// A sequence of chunks is fully specified by the `start` position of the first chunk, the sizes of all chunks and the `stride` between consecutive chunks.
///
/// \note The `chunk_sizes` array is referenced by the sequence, not copied and thus has to be alive for the lifetime of the sequence.
///
/// \param[in] start the position at which the first chunk in the sequence starts
/// \param[in] stride the distance between the start positions of two consecutive chunks in the sequence
/// \param[in] n_chunks the number of chunks in the sequence
/// \param[in] chunk_sizes the individual sizes (number of positions) of all chunks in the sequence
///
/// \returns the newly constructed sequence
_sion_limited_chunk_sequence _sion_limited_chunk_sequence_from_parts(
  int64_t start, int64_t stride, size_t n_chunks, const int64_t *chunk_sizes);

/// \brief construct a limited chunk sequence for an open file
///
/// Exctracts the information necessary to specify the limited chunk sequence from an open file (specifically, the currently open logical file, i.e. `fd->startpos`, `fd->globalskip`, `fd->lastchunknr`, `fd->blocksizes`).
///
/// \param[in] fd the file descriptor to exctract the information from
///
/// \returns the newly constructed sequence
_sion_limited_chunk_sequence _sion_limited_chunk_sequence_from_filedesc(const _sion_filedesc *fd);

/// \brief tests whether a physical positions lies outside a limited chunk sequence
///
/// Returns true if the physical position lies beyond the last chunk in the sequence.
///
/// \param[in] sequence the limited chunk sequence
/// \param[in] physical_position the physical position to test
///
/// \returns whether the position lies beyond the last chunk in the sequence
bool _sion_limited_chunk_sequence_position_oob(const _sion_limited_chunk_sequence *sequence, int64_t physical_position);

/// \brief translate physical address to logical address
///
/// Maps an address in a physical file to an address in a logical file contained therein using the parameters of the given chunk
/// sequence.
/// Physical addresses that lie between two chunks in the sequence are mapped to the first address in the next chunk.
/// If the physical position lies beyond the end of the limited chunk sequence, the logical position corresponding to
/// the last physical position in the sequence is returned.
///
/// \param[in] sequence specifies the sequence of chunks in the physical file that belong to the logical file to map into
/// \param[in] physical_position position in the physical file that shall be translated into a position in the logical file
///
/// \returns a position in the logical file that corresponds to `physical_position`
int64_t _sion_limited_chunk_sequence_translate_p2l(const _sion_limited_chunk_sequence *sequence, int64_t physical_position);

/// \brief translate physical address to a chunk number
///
/// Maps an address in a physical file to the number of the chunk it lies in, or if it lies between two chunks in the sequence it
/// is mapped to the number of the next chunk.
///
/// \attention `physical_position` must not lie beyond the last chunk in the sequence.
///
/// \param[in] sequence specifies the sequence of chunks in the physical file that belong to the logical file to map into
/// \param[in] physical_position position in the physical file that shall be translated into a chunk number
///
/// \returns a chunk number that corresponds to `physical_position`
int32_t _sion_limited_chunk_sequence_translate_p2n(const _sion_limited_chunk_sequence *sequence, int64_t physical_position);

/// \brief looks up a chunk in a sequence by its chunk number
///
/// \attention `chunk_number` must be less than `sequence->n_chunks`.
///
/// \param[in] sequence the sequence in which to look up the chunk
/// \param[in] chunk_number the number of the chunk to look up
///
/// \returns a range encompassing the chunk of the desired number `range(sequence->start + chunk_number * sequence->stride, sequence->chunk_sizes[chunk_number])`
_sion_range _sion_limited_chunk_sequence_chunk_from_number(const _sion_limited_chunk_sequence *sequence, int32_t chunk_number);

/// \brief looks up a chunk (or its remainder) in a sequence by physical position
///
/// Maps the physical position to a chunk in the sequence. If the physical position lies between two chunks, the entire next chunk
/// is returned, otherwise the remainder of the chunk the position lies in, beyond the position.
///
/// \param[in] sequence the sequence in which to look up the chunk
/// \param[in] physical_position the physical position at which to look up the chunk
///
/// \returns a range encompasing a chunk or the remainder of a chunk corresponding to the physical position
_sion_range _sion_limited_chunk_sequence_chunk_from_physical_position(
  const _sion_limited_chunk_sequence *sequence, int64_t physical_position);

/// \brief construct a range iterator from basic parts
///
/// The resulting iterator will yield ranges from the specified `sequence`, starting at the given `position` which in sum contain `amount` positions.
///
/// \param[in] sequence the sequence of chunks to yield ranges from
/// \param[in] position the position in the physical file to start the first range at
/// \param[in] amount how many positions from the file the ranges yielded from this iterator should contain
///
/// \returns the newly constructed iterator
_sion_range_iterator _sion_range_iterator_from_parts(_sion_chunk_sequence sequence, int64_t position, int64_t amount);

/// \brief construct a range iterator from an open file
///
/// Extracts the necessary information from the filedescriptor (specifically, the currently open logical file, i.e. `fd->currentpos` and see also _sion_chunk_sequence_from_filedesc()).
/// The number of positions still has to be specified.
///
/// \param[in] fd the file descriptor to exctract the information from
/// \param[in] amount how many positions from the file the ranges yielded from this iterator should contain
///
/// \returns the newly constructed iterator
///
/// \see _sion_range_iterator_from_parts
_sion_range_iterator _sion_range_iterator_from_filedesc(const _sion_filedesc *fd, int64_t amount);

/// \brief yields the next range
///
/// This function should be called repeatedly in a loop to either yield the next range from the sequence or indicate that the iterator has been exhausted.
///
/// \code
///   _sion_range_iterator ranges = _sion_range_iterator_from_filedesc(fd, 42);
///   _sion_range range;
///   while (_sion_range_iterator_next(&ranges, &range) {
///     // do something with the positions between range.start and range.start + range.length
///   }
/// \endcode
///
/// \param[in,out] self the iterator to yield ranges from
/// \param[out] next the next range in the sequence
///
/// \returns `_SION_EXHAUSTED` if the iterator has been exhausted, otherwise the kind of the next range
///
/// \see _sion_range_kind
_sion_range_kind _sion_range_iterator_next(_sion_range_iterator *self, _sion_range *next);

/// \brief construct a partitioned range iterator from basic parts
///
/// The resulting iterator will yield the ranges yielded by a similarly construced \ref _sion_range_iterator with each range split into sub-ranges of at most `partition` positions.
///
/// \param[in] sequence the sequence of chunks to yield ranges from
/// \param[in] position the position in the physical file to start the first range at
/// \param[in] amount how many positions from the file the ranges yielded from this iterator should contain
/// \param[in] partition maximum size of a range yielded by the constructed iterator
///
/// \returns the newly constructed iterator
///
/// \see _sion_range_iterator_from_parts
_sion_partitioned_range_iterator _sion_partitioned_range_iterator_from_parts(
  _sion_chunk_sequence sequence, int64_t position, int64_t amount, int64_t partition);

/// \brief construct a partitioned range iterator from an open file
///
/// Extracts the necessary information from the filedescriptor (specifically, the currently open logical file, i.e. `fd->currentpos` and see also _sion_chunk_sequence_from_filedesc()).
/// The number of positions and the maximum size of the ranges still have to be specified.
///
/// \param[in] fd the file descriptor to exctract the information from
/// \param[in] amount how many positions from the file the ranges yielded from this iterator should contain
/// \param[in] partition maximum size of a range yielded by the constructed iterator
///
/// \returns the newly constructed iterator
///
/// \see _sion_partitioned_range_iterator_from_parts
_sion_partitioned_range_iterator _sion_partitioned_range_iterator_from_filedesc(
  const _sion_filedesc *fd, int64_t amount, int64_t partition);

/// \brief yields the next range
///
/// This function should be called repeatedly in a loop to either yield the next range from the sequence or indicate that the iterator has been exhausted.
///
/// \code
///   _sion_partitioned_range_iterator ranges = _sion_partitioned_range_iterator_from_filedesc(fd, 42, 23);
///   _sion_range range;
///   while (_sion_partitioned_range_iterator_next(&ranges, &range) {
///     // do something with the positions between range.start and range.start + range.length
///   }
/// \endcode
///
/// \param[in,out] self the iterator to yield ranges from
/// \param[out] next the next range in the sequence
///
/// \returns `_SION_EXHAUSTED` if the iterator has been exhausted, otherwise the kind of the next range
///
/// \see _sion_range_kind
_sion_range_kind _sion_partitioned_range_iterator_next(_sion_partitioned_range_iterator *self, _sion_range *next);

/// \brief construct a limited range iterator from basic parts
///
/// The resulting iterator will yield ranges from the specified `sequence`, starting at the given `position` which in sum contain `amount` positions.
/// Unlike \ref _sion_range_iterator, each chunk in the sequence can have an individual size specified through an additional sequence of chunk sizes.
///
/// \param[in] sequence the sequence of chunks to yield ranges from
/// \param[in] position the position in the physical file to start the first range at
/// \param[in] amount how many positions from the file the ranges yielded from this iterator should contain
///
/// \returns the newly constructed iterator
_sion_limited_range_iterator _sion_limited_range_iterator_from_parts(
  _sion_limited_chunk_sequence sequence, int64_t position, int64_t amount);

/// \brief construct a limited range iterator from an open file
///
/// Extracts the necessary information from the filedescriptor (specifically, the currently open logical file, i.e. `fd->currentpos` and `fd->blocksizes` and see also _sion_chunk_sequence_from_filedesc()).
/// The number of positions still has to be specified.
///
/// \param[in] fd the file descriptor to exctract the information from
/// \param[in] amount how many positions from the file the ranges yielded from this iterator should contain
///
/// \returns the newly constructed iterator
///
/// \see _sion_limited_range_iterator_from_parts
_sion_limited_range_iterator _sion_limited_range_iterator_from_filedesc(const _sion_filedesc *fd, int64_t amount);

/// \brief yields the next range
///
/// This function should be called repeatedly in a loop to either yield the next range from the sequence or indicate that the iterator has been exhausted.
///
/// \code
///   _sion_limited_range_iterator ranges = _sion_limited_range_iterator_from_filedesc(fd, 42);
///   _sion_range range;
///   while (_sion_limited_range_iterator_next(&ranges, &range) {
///     // do something with the positions between range.start and range.start + range.length
///   }
/// \endcode
///
/// \param[in,out] self the iterator to yield ranges from
/// \param[out] next the next range in the sequence
///
/// \returns `_SION_EXHAUSTED` if the iterator has been exhausted, otherwise the kind of the next range
///
/// \see _sion_range_kind
_sion_range_kind _sion_limited_range_iterator_next(_sion_limited_range_iterator *self, _sion_range *next);

/// \brief construct a partitioned limited range iterator from basic parts
///
/// The resulting iterator will yield the ranges yielded by a similarly construced \ref _sion_limited_range_iterator with each range split into sub-ranges of at most `partition` positions.
///
/// \param[in] sequence the sequence of chunks to yield ranges from (used for start positions)
/// \param[in] position the position in the physical file to start the first range at
/// \param[in] amount how many positions from the file the ranges yielded from this iterator should contain
/// \param[in] partition maximum size of a range yielded by the constructed iterator
///
/// \returns the newly constructed iterator
///
/// \see _sion_limited_range_iterator_from_parts
_sion_partitioned_limited_range_iterator _sion_partitioned_limited_range_iterator_from_parts(
  _sion_limited_chunk_sequence sequence, int64_t position, int64_t amount, int64_t partition);

/// \brief construct a partitioned limited range iterator from an open file
///
/// Extracts the necessary information from the filedescriptor (specifically, the currently open logical file, i.e. `fd->currentpos` and `fd->blocksizes` and see also _sion_chunk_sequence_from_filedesc()).
/// The number of positions and the maximum size of the ranges still have to be specified.
///
/// \param[in] fd the file descriptor to exctract the information from
/// \param[in] amount how many positions from the file the ranges yielded from this iterator should contain
/// \param[in] partition maximum size of a range yielded by the constructed iterator
///
/// \returns the newly constructed iterator
///
/// \see _sion_partitioned_limited_range_iterator_from_parts
_sion_partitioned_limited_range_iterator _sion_partitioned_limited_range_iterator_from_filedesc(
  const _sion_filedesc *fd, int64_t amount, int64_t partition);

/// \brief yields the next range
///
/// This function should be called repeatedly in a loop to either yield the next range from the sequence or indicate that the iterator has been exhausted.
///
/// \code
///   _sion_partitioned_limited_range_iterator ranges = _sion_partitioned_limited_range_iterator_from_filedesc(fd, 42, 23);
///   _sion_range range;
///   while (_sion_partitioned_limited_range_iterator_next(&ranges, &range) {
///     // do something with the positions between range.start and range.start + range.length
///   }
/// \endcode
///
/// \param[in,out] self the iterator to yield ranges from
/// \param[out] next the next range in the sequence
///
/// \returns `_SION_EXHAUSTED` if the iterator has been exhausted, otherwise the kind of the next range
///
/// \see _sion_range_kind
_sion_range_kind _sion_partitioned_limited_range_iterator_next(_sion_partitioned_limited_range_iterator *self, _sion_range *next);

/// \brief get the position of the file pointer in the currently opened logical file
///
/// This is a convenience function that queries the current position of the file pointer in the physical file and translates it
/// into a position in the currently opened logical file via _sion_chunk_sequence_translate_p2l.
///
/// \attention This function only works on files that are opened in write mode.
///
/// \param[in] filedesc the file descriptor to inspect
///
/// \returns the current position of the filepointer in the logical file
int64_t _sion_get_logical_position(const _sion_filedesc *filedesc);

/// \brief get the number of the chunk that the file pointer currently rests in (or will move to next)
///
/// This is a convenience function that queries the current position of the file pointer in the physical file and translates it
/// into a chunk number via _sion_chunk_sequence_translate_p2n.
///
/// \param[in] filedesc the file descriptor to inspect
///
/// \returns number of the chunk that the file pointer currently rests in (or will move to next)
int32_t _sion_get_current_chunk_number(const _sion_filedesc *filedesc);

/// \brief get a range that encompasses the chunk the file pointer currently rests in (or will move to next)
///
/// This is a convenience function that queries the current position of the file pointer in the physical file and translates it
/// into a chunk number via _sion_chunk_sequence_translate_p2n and constructs a range encompassing the chunk of that number using
/// _sion_chunk_sequence_chunk_from_number.
///
/// \param[in] filedesc the file descriptor to inspect
///
/// \returns a range encompassing th chunk that the file pointer currently rests in (or will move to next)
_sion_range _sion_get_current_chunk(const _sion_filedesc *filedesc);

#endif

/// \endcond
