Bug #8305 (Implement cache), r: valeski, rickg

The storage stream provides an internal buffer that
can be filled by a client using a single output
stream.  One or more independent input streams can
be created to read the data out non-destructively.
The implementation uses a segmented buffer
internally to avoid realloc'ing of large buffers.
This commit is contained in:
fur%netscape.com 1999-11-16 19:12:41 +00:00
parent 362d7a861c
commit 8e84de48cf
6 changed files with 638 additions and 1 deletions

361
xpcom/io/nsBinaryStream.cpp Normal file
View File

@ -0,0 +1,361 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
*/
/**
* This file contains implementations of the nsIBinaryInputStream and
* nsIBinaryOutputStream interfaces. Together, these interfaces allows reading
* and writing of primitive data types (integers, floating-point values,
* booleans, etc.) to a stream in a binary, untagged, fixed-endianness format.
* This might be used, for example, to implement network protocols or to
* produce architecture-neutral binary disk files, i.e. ones that can be read
* and written by both big-endian and little-endian platforms. Output is
* written in big-endian order (high-order byte first), as this is traditional
* network order.
*
* @See nsIBinaryInputStream
* @See nsIBinaryOutputStream
*/
#include "nsBinaryStream.h"
#include "nsIAllocator.h"
// Swap macros, used to convert to/from canonical (big-endian) format
#ifdef IS_LITTLE_ENDIAN
# define SWAP16(x) ((((x) & 0xff) << 8) | (((x) >> 8) & 0xff))
# define SWAP32(x) ((SWAP16((x) & 0xffff) << 16) | (SWAP16((x) >> 16)))
#else
# ifndef IS_BIG_ENDIAN
# error "Unknown endianness"
# endif
# define SWAP16(x) (x)
# define SWAP32(x) (x)
#endif
nsBinaryOutputStream::nsBinaryOutputStream(nsIOutputStream* aStream): mOutputStream(aStream)
{
NS_INIT_REFCNT();
}
NS_IMPL_ISUPPORTS(nsBinaryOutputStream, NS_GET_IID(nsIBinaryOutputStream))
NS_IMETHODIMP
nsBinaryOutputStream::Flush() { return mOutputStream->Flush(); }
NS_IMETHODIMP
nsBinaryOutputStream::Close() { return mOutputStream->Close(); }
NS_IMETHODIMP
nsBinaryOutputStream::Write(const char *aBuf, PRUint32 aCount, PRUint32 *aActualBytes)
{
return mOutputStream->Write(aBuf, aCount, aActualBytes);
}
NS_IMETHODIMP
nsBinaryOutputStream::SetOutputStream(nsIOutputStream *aOutputStream)
{
NS_ENSURE_ARG_POINTER(aOutputStream);
mOutputStream = aOutputStream;
return NS_OK;
}
NS_IMETHODIMP
nsBinaryOutputStream::WriteBoolean(PRBool aBoolean)
{
return Write8(aBoolean);
}
NS_IMETHODIMP
nsBinaryOutputStream::Write8(PRUint8 aByte)
{
nsresult rv;
PRUint32 bytesWritten;
rv = Write((const char*)&aByte, sizeof aByte, &bytesWritten);
if (bytesWritten != sizeof aByte)
return NS_ERROR_FAILURE;
return rv;
}
NS_IMETHODIMP
nsBinaryOutputStream::Write16(PRUint16 a16)
{
nsresult rv;
PRUint32 bytesWritten;
a16 = SWAP16(a16);
rv = Write((const char*)&a16, sizeof a16, &bytesWritten);
if (bytesWritten != sizeof a16)
return NS_ERROR_FAILURE;
return rv;
}
NS_IMETHODIMP
nsBinaryOutputStream::Write32(PRUint32 a32)
{
nsresult rv;
PRUint32 bytesWritten;
a32 = SWAP32(a32);
rv = Write((const char*)&a32, sizeof a32, &bytesWritten);
if (bytesWritten != sizeof a32)
return NS_ERROR_FAILURE;
return rv;
}
NS_IMETHODIMP
nsBinaryOutputStream::Write64(PRUint64 a64)
{
nsresult rv;
PRUint32* raw32 = (PRUint32*)&a64;
#ifdef IS_BIG_ENDIAN
rv = Write32(raw32[0]);
if (NS_FAILED(rv)) return rv;
return Write32(raw32[1]);
#else
rv = Write32(raw32[1]);
if (NS_FAILED(rv)) return rv;
return Write32(raw32[0]);
#endif
}
NS_IMETHODIMP
nsBinaryOutputStream::WriteFloat(float aFloat)
{
NS_ASSERTION(sizeof(float) == sizeof (PRUint32),
"False assumption about sizeof(float)");
return Write32(*NS_REINTERPRET_CAST(PRUint32*, &aFloat));
}
NS_IMETHODIMP
nsBinaryOutputStream::WriteDouble(double aDouble)
{
NS_ASSERTION(sizeof(double) == sizeof(PRUint64),
"False assumption about sizeof(double)");
return Write64(*NS_REINTERPRET_CAST(PRUint64*,&aDouble));
}
NS_IMETHODIMP
nsBinaryOutputStream::WriteStringZ(const char *aString)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsBinaryOutputStream::WriteWStringZ(const PRUnichar* aString)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsBinaryOutputStream::WriteUtf8Z(const PRUnichar* aString)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsBinaryOutputStream::WriteBytes(const char *aString, PRUint32 aLength)
{
nsresult rv;
PRUint32 bytesWritten;
rv = Write(aString, aLength, &bytesWritten);
if (bytesWritten != aLength)
return NS_ERROR_FAILURE;
return rv;
}
NS_IMETHODIMP
nsBinaryOutputStream::WriteString(nsString* aString)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
nsBinaryInputStream::nsBinaryInputStream(nsIInputStream* aStream): mInputStream(aStream) { NS_INIT_REFCNT(); }
NS_IMPL_ISUPPORTS(nsBinaryInputStream, NS_GET_IID(nsIBinaryInputStream))
NS_IMETHODIMP
nsBinaryInputStream::Available(PRUint32* aResult) { return mInputStream->Available(aResult); }
NS_IMETHODIMP
nsBinaryInputStream::Read(char* aBuffer, PRUint32 aCount, PRUint32 *aNumRead)
{
return mInputStream->Read(aBuffer, aCount, aNumRead);
}
NS_IMETHODIMP
nsBinaryInputStream::Close() { return mInputStream->Close(); }
NS_IMETHODIMP
nsBinaryInputStream::SetInputStream(nsIInputStream *aInputStream)
{
NS_ENSURE_ARG_POINTER(aInputStream);
mInputStream = aInputStream;
return NS_OK;
}
NS_IMETHODIMP
nsBinaryInputStream::ReadBoolean(PRBool* aBoolean)
{
PRUint8 byteResult;
nsresult rv = Read8(&byteResult);
*aBoolean = byteResult;
return rv;
}
NS_IMETHODIMP
nsBinaryInputStream::Read8(PRUint8* aByte)
{
nsresult rv;
PRUint32 bytesRead;
rv = Read((char*)aByte, sizeof(*aByte), &bytesRead);
if (bytesRead != sizeof (*aByte))
return NS_ERROR_FAILURE;
return rv;
}
NS_IMETHODIMP
nsBinaryInputStream::Read16(PRUint16* a16)
{
nsresult rv;
PRUint32 bytesRead;
rv = Read((char*)a16, sizeof *a16, &bytesRead);
if (bytesRead != sizeof *a16)
return NS_ERROR_FAILURE;
*a16 = SWAP16(*a16);
return rv;
}
NS_IMETHODIMP
nsBinaryInputStream::Read32(PRUint32* a32)
{
nsresult rv;
PRUint32 bytesRead;
rv = Read((char*)a32, sizeof *a32, &bytesRead);
if (bytesRead != sizeof *a32)
return NS_ERROR_FAILURE;
*a32 = SWAP32(*a32);
return rv;
}
NS_IMETHODIMP
nsBinaryInputStream::Read64(PRUint64* a64)
{
nsresult rv;
PRUint32* raw32 = (PRUint32*)a64;
#ifdef IS_BIG_ENDIAN
rv = Read32(&raw32[0]);
if (NS_FAILED(rv)) return rv;
return Read32(&raw32[1]);
#else
rv = Read32(&raw32[1]);
if (NS_FAILED(rv)) return rv;
return Read32(&raw32[0]);
#endif
}
NS_IMETHODIMP
nsBinaryInputStream::ReadFloat(float* aFloat)
{
NS_ASSERTION(sizeof(float) == sizeof (PRUint32),
"False assumption about sizeof(float)");
return Read32(NS_REINTERPRET_CAST(PRUint32*, aFloat));
}
NS_IMETHODIMP
nsBinaryInputStream::ReadDouble(double* aDouble)
{
NS_ASSERTION(sizeof(double) == sizeof(PRUint64),
"False assumption about sizeof(double)");
return Read64(NS_REINTERPRET_CAST(PRUint64*, aDouble));
}
NS_IMETHODIMP
nsBinaryInputStream::ReadStringZ(char* *aString)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsBinaryInputStream::ReadWStringZ(PRUnichar* *aString)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsBinaryInputStream::ReadUtf8Z(PRUnichar* *aString)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsBinaryInputStream::ReadBytes(char* *aString, PRUint32 aLength)
{
nsresult rv;
PRUint32 bytesRead;
char* s;
s = (char*)nsAllocator::Alloc(aLength);
if (!s)
return NS_ERROR_OUT_OF_MEMORY;
rv = Read(s, aLength, &bytesRead);
if (NS_FAILED(rv)) return rv;
if (bytesRead != aLength)
return NS_ERROR_FAILURE;
*aString = s;
return NS_OK;
}
NS_IMETHODIMP
nsBinaryInputStream::ReadString(nsString* *aString)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_COM nsresult
NS_NewBinaryOutputStream(nsIBinaryOutputStream* *aResult, nsIOutputStream* aDestStream)
{
NS_ENSURE_ARG_POINTER(aResult);
nsIBinaryOutputStream *stream = new nsBinaryOutputStream(aDestStream);
if (!stream)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(stream);
*aResult = stream;
return NS_OK;
}
NS_COM nsresult
NS_NewBinaryInputStream(nsIBinaryInputStream* *aResult, nsIInputStream* aSrcStream)
{
NS_ENSURE_ARG_POINTER(aResult);
nsIBinaryInputStream *stream = new nsBinaryInputStream(aSrcStream);
if (!stream)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(stream);
*aResult = stream;
return NS_OK;
}

72
xpcom/io/nsBinaryStream.h Normal file
View File

@ -0,0 +1,72 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
*/
#include "nsIBinaryInputStream.h"
#include "nsIBinaryOutputStream.h"
#include "nsCOMPtr.h"
class nsBinaryOutputStream : public nsIBinaryOutputStream
{
public:
nsBinaryOutputStream(nsIOutputStream *aStream);
~nsBinaryOutputStream() {};
private:
// nsISupports methods
NS_DECL_ISUPPORTS
// nsIBaseStream methods
NS_DECL_NSIBASESTREAM
// nsIOutputStream methods
NS_DECL_NSIOUTPUTSTREAM
// nsIBinaryOutputStream methods
NS_DECL_NSIBINARYOUTPUTSTREAM
protected:
nsCOMPtr<nsIOutputStream> mOutputStream;
};
class nsBinaryInputStream : public nsIBinaryInputStream
{
public:
nsBinaryInputStream(nsIInputStream *aStream);
~nsBinaryInputStream() {};
private:
// nsISupports methods
NS_DECL_ISUPPORTS
// nsIBaseStream methods
NS_DECL_NSIBASESTREAM
// nsIInputStream methods
NS_DECL_NSIINPUTSTREAM
// nsIBinaryInputStream methods
NS_DECL_NSIBINARYINPUTSTREAM
protected:
nsCOMPtr<nsIInputStream> mInputStream;
};

View File

@ -0,0 +1,85 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
*/
[ptr] native nsString(nsString);
%{ C++
#include "nsString.h"
%}
#include "nsIOutputStream.idl"
#include "nsrootidl.idl"
/**
* This interface allows consumption of primitive data types from a "binary
* stream" containing untagged, big-endian binary data, i.e. as produced by an
* implementation of nsIBinaryOutputStream. This might be used, for example,
* to implement network protocols or to read from architecture-neutral disk
* files, i.e. ones that can be read and written by both big-endian and
* little-endian platforms.
*
* @See nsIBinaryOutputStream
*/
[scriptable, uuid(7b456cb0-8772-11d3-90cf-0040056a906e)]
interface nsIBinaryInputStream : nsIInputStream {
void setInputStream(in nsIInputStream aInputStream);
PRBool readBoolean();
PRUint8 read8();
PRUint16 read16();
PRUint32 read32();
PRUint64 read64();
float readFloat();
double readDouble();
/**
* Read a NUL-terminated 8-bit char* string from a binary stream.
*/
string readStringZ();
/**
* Read a NUL-terminated 16-bit PRUnichar* string from a binary stream.
*/
wstring readWStringZ();
/**
* Read a NUL-terminated UTF8-encoded string from a binary stream, producing
* a NUL-terminated 16-bit PRUnichar* string argument as a result.
*/
wstring readUtf8Z();
/**
* Read an opaque byte array from a binary stream.
*/
void readBytes([size_is(aLength)] out string aString, in PRUint32 aLength);
/**
* Read a string (possibly containing embedded NULs) from a binary stream.
*/
[noscript] nsString readString();
};
%{C++
NS_COM nsresult
NS_NewBinaryInputStream(nsIBinaryInputStream* *aResult, nsIInputStream* aSrcStream);
%}

View File

@ -0,0 +1,86 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
*/
[ptr] native nsString(nsString);
%{ C++
#include "nsString.h"
%}
#include "nsIOutputStream.idl"
#include "nsrootidl.idl"
/**
* This interface allows writing of primitive data types (integers,
* floating-point values, booleans, etc.) to a stream in a binary, untagged,
* fixed-endianness format. This might be used, for example, to implement
* network protocols or to produce architecture-neutral binary disk files,
* i.e. ones that can be read and written by both big-endian and little-endian
* platforms. Output is written in big-endian order (high-order byte first),
* as this is traditional network order.
*
* @See nsIBinaryInputStream
*/
[scriptable, uuid(204ee610-8765-11d3-90cf-0040056a906e)]
interface nsIBinaryOutputStream : nsIOutputStream {
void setOutputStream(in nsIOutputStream aOutputStream);
void writeBoolean(in PRBool aBoolean);
void write8(in PRUint8 aByte);
void write16(in PRUint16 a16);
void write32(in PRUint32 a32);
void write64(in PRUint64 a64);
void writeFloat(in float aFloat);
void writeDouble(in double aDouble);
/**
* Write a NUL-terminated 8-bit char* string to a binary stream.
*/
void writeStringZ(in string aString);
/**
* Write a NUL-terminated 16-bit PRUnichar* string to a binary stream.
*/
void writeWStringZ(in wstring aString);
/**
* Write a NUL-terminated UTF8-encoded string to a binary stream, produced
* from a NUL-terminated 16-bit PRUnichar* string argument.
*/
void writeUtf8Z(in wstring aString);
/**
* Write an opaque byte array to a binary stream.
*/
void writeBytes([size_is(aLength)] in string aString, in PRUint32 aLength);
/**
* Write a string (possibly containing embedded NULs) to a binary stream.
*/
[noscript] void writeString(in nsString aString);
};
%{C++
NS_COM nsresult
NS_NewBinaryOutputStream(nsIBinaryOutputStream* *aResult, nsIOutputStream* aDestStream);
%}

View File

@ -125,6 +125,32 @@ nsSegmentedBuffer::DeleteFirstSegment()
}
}
PRBool
nsSegmentedBuffer::DeleteLastSegment()
{
PRInt32 last = ModSegArraySize(mLastSegmentIndex - 1);
NS_ASSERTION(mSegmentArray[last] != nsnull, "deleting bad segment");
(void)mSegAllocator->Free(mSegmentArray[last]);
mSegmentArray[last] = nsnull;
mLastSegmentIndex = last;
return (PRBool)(mLastSegmentIndex == mFirstSegmentIndex);
}
PRBool
nsSegmentedBuffer::ReallocLastSegment(size_t newSize)
{
PRInt32 last = ModSegArraySize(mLastSegmentIndex - 1);
NS_ASSERTION(mSegmentArray[last] != nsnull, "realloc'ing bad segment");
char *newSegment =
(char*)mSegAllocator->Realloc(mSegmentArray[last], newSize);
if (newSegment) {
mSegmentArray[last] = newSegment;
return PR_TRUE;
} else {
return PR_FALSE;
}
}
void
nsSegmentedBuffer::Empty()
{

View File

@ -40,6 +40,13 @@ public:
// returns true if no more segments remain:
PRBool DeleteFirstSegment(); // pops from beginning
// returns true if no more segments remain:
PRBool DeleteLastSegment(); // pops from beginning
// Call Realloc() on last segment. This is used to reduce memory
// consumption when data is not an exact multiple of segment size.
PRBool ReallocLastSegment(size_t newSize);
void Empty(); // frees all segments
PRUint32 GetSegmentCount() {
@ -68,7 +75,7 @@ protected:
return result;
}
PRBool IsFull() {
PRBool IsFull() {
return ModSegArraySize(mLastSegmentIndex + 1) == mFirstSegmentIndex;
}