From 14d73e7f5bf3e4e8fdec85fd2d5dc442cb9a1517 Mon Sep 17 00:00:00 2001 From: "warren%netscape.com" Date: Wed, 9 Jun 1999 04:52:47 +0000 Subject: [PATCH] Added ReadSegments and WriteSegments to nsIBuffer to avoid the need to allocate intermediate buffers. git-svn-id: svn://10.0.0.236/trunk@34369 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/xpcom/ds/nsBuffer.cpp | 149 ++++++++++++++++++++++++++++++ mozilla/xpcom/ds/nsBuffer.h | 5 +- mozilla/xpcom/ds/nsIBuffer.h | 25 +++++ mozilla/xpcom/tests/TestPipes.cpp | 18 +++- 4 files changed, 195 insertions(+), 2 deletions(-) diff --git a/mozilla/xpcom/ds/nsBuffer.cpp b/mozilla/xpcom/ds/nsBuffer.cpp index 7835bcd0157..b5259e0d5a2 100644 --- a/mozilla/xpcom/ds/nsBuffer.cpp +++ b/mozilla/xpcom/ds/nsBuffer.cpp @@ -147,9 +147,70 @@ nsBuffer::PopReadSegment() //////////////////////////////////////////////////////////////////////////////// // nsIBuffer methods: +NS_IMETHODIMP +nsBuffer::ReadSegments(nsWriteSegmentFun writer, void* closure, PRUint32 count, + PRUint32 *readCount) +{ + nsresult rv; + PRUint32 readBufferLen; + char* readBuffer; + + *readCount = 0; + while (count > 0) { + rv = GetReadBuffer(0, &readBuffer, &readBufferLen); + if (rv == NS_BASE_STREAM_EOF) // all we're going to get + return *readCount > 0 ? NS_OK : NS_BASE_STREAM_EOF; + if (NS_FAILED(rv)) return rv; + + if (readBufferLen == 0) + return mEOF && *readCount == 0 ? NS_BASE_STREAM_EOF : NS_OK; + + readBufferLen = PR_MIN(readBufferLen, count); + while (readBufferLen > 0) { + PRUint32 writeCount; + rv = writer(closure, readBuffer, *readCount, readBufferLen, &writeCount); + if (NS_FAILED(rv)) { + // if we failed to write just report what we were + // able to read so far + return NS_OK; + } + NS_ASSERTION(writeCount <= readBufferLen, "writer returned bad writeCount"); + readBuffer += writeCount; + readBufferLen -= writeCount; + *readCount += writeCount; + count -= writeCount; + + if (mReadCursor + writeCount == mReadSegmentEnd) { + rv = PopReadSegment(); + if (NS_FAILED(rv)) return rv; + } + else { + mReadCursor += writeCount; + } + } + } + return NS_OK; +} + +NS_METHOD +nsWriteToRawBuffer(void* closure, + const char* fromRawSegment, + PRUint32 offset, + PRUint32 count, + PRUint32 *writeCount) +{ + char* toBuf = (char*)closure; + nsCRT::memcpy(&toBuf[offset], fromRawSegment, count); + *writeCount = count; + return NS_OK; +} + NS_IMETHODIMP nsBuffer::Read(char* toBuf, PRUint32 bufLen, PRUint32 *readCount) { +#if 1 + return ReadSegments(nsWriteToRawBuffer, toBuf, bufLen, readCount); +#else nsresult rv; PRUint32 readBufferLen; char* readBuffer; @@ -179,6 +240,7 @@ nsBuffer::Read(char* toBuf, PRUint32 bufLen, PRUint32 *readCount) } } return NS_OK; +#endif } NS_IMETHODIMP @@ -259,9 +321,80 @@ nsBuffer::GetReadBuffer(PRUint32 startPosition, //////////////////////////////////////////////////////////////////////////////// +NS_IMETHODIMP +nsBuffer::WriteSegments(nsReadSegmentFun reader, void* closure, PRUint32 count, + PRUint32 *writeCount) +{ + nsresult rv; + + if (mEOF) + return NS_BASE_STREAM_EOF; + + *writeCount = 0; + while (count > 0) { + PRUint32 writeBufLen; + char* writeBuf; + rv = GetWriteBuffer(0, &writeBuf, &writeBufLen); + if (NS_FAILED(rv)) { + // if we failed to allocate a new segment, we're probably out + // of memory, but we don't care -- just report what we were + // able to write so far + return NS_OK; + } + + writeBufLen = PR_MIN(writeBufLen, count); + while (writeBufLen > 0) { + PRUint32 readCount; + rv = reader(closure, writeBuf, *writeCount, writeBufLen, &readCount); + if (rv == NS_BASE_STREAM_EOF) { + // If the input stream ends, set EOF on the buffer so that + // nsBuffer::Read later notices it. + SetEOF(); + return NS_OK; + } + else if (NS_FAILED(rv)) { + // if we failed to read just report what we were + // able to write so far + return NS_OK; + } + NS_ASSERTION(readCount <= writeBufLen, "reader returned bad readCount"); + writeBuf += readCount; + writeBufLen -= readCount; + *writeCount += readCount; + count -= readCount; + + // set the write cursor after the data is valid + if (mWriteCursor + readCount == mWriteSegmentEnd) { + mWriteSegment = nsnull; // allocate a new segment next time around + mWriteSegmentEnd = nsnull; + mWriteCursor = nsnull; + } + else + mWriteCursor += readCount; + } + } + return NS_OK; +} + +NS_METHOD +nsReadFromRawBuffer(void* closure, + char* toRawSegment, + PRUint32 offset, + PRUint32 count, + PRUint32 *readCount) +{ + const char* fromBuf = (const char*)closure; + nsCRT::memcpy(toRawSegment, &fromBuf[offset], count); + *readCount = count; + return NS_OK; +} + NS_IMETHODIMP nsBuffer::Write(const char* fromBuf, PRUint32 bufLen, PRUint32 *writeCount) { +#if 1 + return WriteSegments(nsReadFromRawBuffer, (void*)fromBuf, bufLen, writeCount); +#else nsresult rv; if (mEOF) @@ -294,11 +427,26 @@ nsBuffer::Write(const char* fromBuf, PRUint32 bufLen, PRUint32 *writeCount) mWriteCursor += count; } return NS_OK; +#endif +} + +NS_METHOD +nsReadFromInputStream(void* closure, + char* toRawSegment, + PRUint32 offset, + PRUint32 count, + PRUint32 *readCount) +{ + nsIInputStream* fromStream = (nsIInputStream*)closure; + return fromStream->Read(toRawSegment, count, readCount); } NS_IMETHODIMP nsBuffer::WriteFrom(nsIInputStream* fromStream, PRUint32 count, PRUint32 *writeCount) { +#if 1 + return WriteSegments(nsReadFromInputStream, fromStream, count, writeCount); +#else nsresult rv; if (mEOF) @@ -341,6 +489,7 @@ nsBuffer::WriteFrom(nsIInputStream* fromStream, PRUint32 count, PRUint32 *writeC mWriteCursor += readCount; } return NS_OK; +#endif } NS_IMETHODIMP diff --git a/mozilla/xpcom/ds/nsBuffer.h b/mozilla/xpcom/ds/nsBuffer.h index 5bea37d2663..4e9fefc050d 100644 --- a/mozilla/xpcom/ds/nsBuffer.h +++ b/mozilla/xpcom/ds/nsBuffer.h @@ -34,11 +34,14 @@ public: // nsIBuffer methods: NS_IMETHOD Init(PRUint32 growBySize, PRUint32 maxSize, nsIAllocator* allocator); + NS_IMETHOD ReadSegments(nsWriteSegmentFun writer, void* closure, PRUint32 count, + PRUint32 *readCount); NS_IMETHOD Read(char* toBuf, PRUint32 bufLen, PRUint32 *readCount); NS_IMETHOD GetReadBuffer(PRUint32 startPosition, char* *result, PRUint32 *readBufferLength); - + NS_IMETHOD WriteSegments(nsReadSegmentFun reader, void* closure, PRUint32 count, + PRUint32 *writeCount); NS_IMETHOD Write(const char* fromBuf, PRUint32 bufLen, PRUint32 *writeCount); NS_IMETHOD WriteFrom(nsIInputStream* fromStream, PRUint32 count, PRUint32 *writeCount); NS_IMETHOD GetWriteBuffer(PRUint32 startPosition, diff --git a/mozilla/xpcom/ds/nsIBuffer.h b/mozilla/xpcom/ds/nsIBuffer.h index 12f1ecef65a..063f4ce9872 100644 --- a/mozilla/xpcom/ds/nsIBuffer.h +++ b/mozilla/xpcom/ds/nsIBuffer.h @@ -46,6 +46,17 @@ class nsIBufferOutputStream; #define NS_BUFFER_PROGID "component://netscape/buffer" #define NS_BUFFER_CLASSNAME "Buffer" +typedef NS_CALLBACK(nsReadSegmentFun)(void* closure, + char* toRawSegment, + PRUint32 fromOffset, + PRUint32 count, + PRUint32 *readCount); +typedef NS_CALLBACK(nsWriteSegmentFun)(void* closure, + const char* fromRawSegment, + PRUint32 toOffset, + PRUint32 count, + PRUint32 *writeCount); + class nsIBuffer : public nsISupports { public: NS_DEFINE_STATIC_IID_ACCESSOR(NS_IBUFFER_IID); @@ -61,11 +72,25 @@ public: NS_IMETHOD Init(PRUint32 growBySize, PRUint32 maxSize, nsIAllocator* allocator) = 0; + /** + * This read method allows you to pass a callback function that gets called + * repeatedly for each buffer segment until the entire amount is read. + * This avoids the need to copy data to/from and intermediate buffer. + */ + NS_IMETHOD ReadSegments(nsWriteSegmentFun writer, void* closure, PRUint32 count, + PRUint32 *readCount) = 0; NS_IMETHOD Read(char* toBuf, PRUint32 bufLen, PRUint32 *readCount) = 0; NS_IMETHOD GetReadBuffer(PRUint32 startPosition, char* *result, PRUint32 *readBufferLength) = 0; + /** + * This write method allows you to pass a callback function that gets called + * repeatedly for each buffer segment until the entire amount is written. + * This avoids the need to copy data to/from and intermediate buffer. + */ + NS_IMETHOD WriteSegments(nsReadSegmentFun reader, void* closure, PRUint32 count, + PRUint32 *writeCount) = 0; NS_IMETHOD Write(const char* fromBuf, PRUint32 bufLen, PRUint32 *writeCount) = 0; NS_IMETHOD WriteFrom(nsIInputStream* fromStream, PRUint32 count, PRUint32 *writeCount) = 0; NS_IMETHOD GetWriteBuffer(PRUint32 startPosition, diff --git a/mozilla/xpcom/tests/TestPipes.cpp b/mozilla/xpcom/tests/TestPipes.cpp index 584cbec1a1c..43c3255d012 100644 --- a/mozilla/xpcom/tests/TestPipes.cpp +++ b/mozilla/xpcom/tests/TestPipes.cpp @@ -168,7 +168,23 @@ main(int argc, char* argv[]) return -1; } #endif - rv = NS_NewPipe2(&in, &out, 4096, 4096 * 4); + // test for small buffers + rv = NS_NewPipe2(&in, &out, 12, 24); + if (NS_FAILED(rv)) { + printf("NewPipe failed\n"); + return -1; + } + + rv = TestPipe(in, out); + NS_RELEASE(in); + NS_RELEASE(out); + if (NS_FAILED(rv)) { + printf("TestPipe failed\n"); + return -1; + } + + // test for large buffers + rv = NS_NewPipe2(&in, &out, 4096, 4096*16); if (NS_FAILED(rv)) { printf("NewPipe failed\n"); return -1;