mirror of
https://github.com/NixOS/nix.git
synced 2025-11-16 15:32:43 +01:00
Source: Add skip() method
This allows FdSource to efficiently skip data we don't care about.
This commit is contained in:
parent
ad2360c59f
commit
daa7e0d2e9
2 changed files with 50 additions and 3 deletions
|
|
@ -97,6 +97,8 @@ struct Source
|
||||||
void drainInto(Sink & sink);
|
void drainInto(Sink & sink);
|
||||||
|
|
||||||
std::string drain();
|
std::string drain();
|
||||||
|
|
||||||
|
virtual void skip(size_t len);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -177,6 +179,7 @@ struct FdSource : BufferedSource
|
||||||
Descriptor fd;
|
Descriptor fd;
|
||||||
size_t read = 0;
|
size_t read = 0;
|
||||||
BackedStringView endOfFileError{"unexpected end-of-file"};
|
BackedStringView endOfFileError{"unexpected end-of-file"};
|
||||||
|
bool isSeekable = true;
|
||||||
|
|
||||||
FdSource()
|
FdSource()
|
||||||
: fd(INVALID_DESCRIPTOR)
|
: fd(INVALID_DESCRIPTOR)
|
||||||
|
|
@ -200,6 +203,8 @@ struct FdSource : BufferedSource
|
||||||
*/
|
*/
|
||||||
bool hasData();
|
bool hasData();
|
||||||
|
|
||||||
|
void skip(size_t len) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
size_t readUnbuffered(char * data, size_t len) override;
|
size_t readUnbuffered(char * data, size_t len) override;
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
|
|
@ -94,9 +94,8 @@ void Source::drainInto(Sink & sink)
|
||||||
{
|
{
|
||||||
std::array<char, 8192> buf;
|
std::array<char, 8192> buf;
|
||||||
while (true) {
|
while (true) {
|
||||||
size_t n;
|
|
||||||
try {
|
try {
|
||||||
n = read(buf.data(), buf.size());
|
auto n = read(buf.data(), buf.size());
|
||||||
sink({buf.data(), n});
|
sink({buf.data(), n});
|
||||||
} catch (EndOfFile &) {
|
} catch (EndOfFile &) {
|
||||||
break;
|
break;
|
||||||
|
|
@ -111,6 +110,16 @@ std::string Source::drain()
|
||||||
return std::move(s.s);
|
return std::move(s.s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Source::skip(size_t len)
|
||||||
|
{
|
||||||
|
std::array<char, 64 * 1024> buf;
|
||||||
|
while (len) {
|
||||||
|
auto n = read(buf.data(), std::min(len, buf.size()));
|
||||||
|
assert(n <= len);
|
||||||
|
len -= n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
size_t BufferedSource::read(char * data, size_t len)
|
size_t BufferedSource::read(char * data, size_t len)
|
||||||
{
|
{
|
||||||
if (!buffer)
|
if (!buffer)
|
||||||
|
|
@ -120,7 +129,7 @@ size_t BufferedSource::read(char * data, size_t len)
|
||||||
bufPosIn = readUnbuffered(buffer.get(), bufSize);
|
bufPosIn = readUnbuffered(buffer.get(), bufSize);
|
||||||
|
|
||||||
/* Copy out the data in the buffer. */
|
/* Copy out the data in the buffer. */
|
||||||
size_t n = len > bufPosIn - bufPosOut ? bufPosIn - bufPosOut : len;
|
auto n = std::min(len, bufPosIn - bufPosOut);
|
||||||
memcpy(data, buffer.get() + bufPosOut, n);
|
memcpy(data, buffer.get() + bufPosOut, n);
|
||||||
bufPosOut += n;
|
bufPosOut += n;
|
||||||
if (bufPosIn == bufPosOut)
|
if (bufPosIn == bufPosOut)
|
||||||
|
|
@ -191,6 +200,39 @@ bool FdSource::hasData()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FdSource::skip(size_t len)
|
||||||
|
{
|
||||||
|
/* Discard data in the buffer. */
|
||||||
|
if (len && buffer && bufPosIn - bufPosOut) {
|
||||||
|
if (len >= bufPosIn - bufPosOut) {
|
||||||
|
len -= bufPosIn - bufPosOut;
|
||||||
|
bufPosIn = bufPosOut = 0;
|
||||||
|
} else {
|
||||||
|
bufPosOut += len;
|
||||||
|
len = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
/* If we can, seek forward in the file to skip the rest. */
|
||||||
|
if (isSeekable && len) {
|
||||||
|
if (lseek(fd, len, SEEK_CUR) == -1) {
|
||||||
|
if (errno == ESPIPE)
|
||||||
|
isSeekable = false;
|
||||||
|
else
|
||||||
|
throw SysError("seeking forward in file");
|
||||||
|
} else {
|
||||||
|
read += len;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Otherwise, skip by reading. */
|
||||||
|
if (len)
|
||||||
|
BufferedSource::skip(len);
|
||||||
|
}
|
||||||
|
|
||||||
size_t StringSource::read(char * data, size_t len)
|
size_t StringSource::read(char * data, size_t len)
|
||||||
{
|
{
|
||||||
if (pos == s.size())
|
if (pos == s.size())
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue