Commit b60bcc27 authored by Milo Yip's avatar Milo Yip

Add MemoryBuffer and MemoryStream

parent c4ce48cd
#ifndef RAPIDJSON_MEMORYBUFFER_H_
#define RAPIDJSON_MEMORYBUFFER_H_
#include "rapidjson.h"
#include "internal/stack.h"
namespace rapidjson {
//! Represents an in-memory output byte stream.
/*!
This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream.
It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file.
Differences between MemoryBuffer and StringBuffer:
1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer.
2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator.
\tparam Allocator type for allocating memory buffer.
\note implements Stream concept
*/
template <typename Allocator = CrtAllocator>
struct GenericMemoryBuffer {
typedef char Ch; // byte
GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
void Put(Ch c) { *stack_.template Push<Ch>() = c; }
void Flush() {}
void Clear() { stack_.Clear(); }
Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
void Pop(size_t count) { stack_.template Pop<Ch>(count); }
const Ch* GetBuffer() const {
return stack_.template Bottom<Ch>();
}
size_t GetSize() const { return stack_.GetSize(); }
static const size_t kDefaultCapacity = 256;
mutable internal::Stack<Allocator> stack_;
};
typedef GenericMemoryBuffer<> MemoryBuffer;
//! Implement specialized version of PutN() with memset() for better performance.
template<>
inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) {
memset(memoryBuffer.stack_.Push<char>(n), c, n * sizeof(c));
}
} // namespace rapidjson
#endif // RAPIDJSON_MEMORYBUFFER_H_
#ifndef RAPIDJSON_MEMORYSTREAM_H_
#define RAPIDJSON_MEMORYSTREAM_H_
#include "rapidjson.h"
namespace rapidjson {
//! Represents an in-memory input byte stream.
/*!
This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream.
It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file.
Differences between MemoryStream and StringStream:
1. StringStream has encoding but MemoryStream is a byte stream.
2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source.
3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4().
\note implements Stream concept
*/
struct MemoryStream {
typedef char Ch; // byte
MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {}
Ch Peek() const { return *src_; }
Ch Take() { return (src_ == end_) ? '\0' : *src_++; }
size_t Tell() const { return static_cast<size_t>(src_ - begin_); }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
void Put(Ch) { RAPIDJSON_ASSERT(false); }
void Flush() { RAPIDJSON_ASSERT(false); }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
// For encoding detection only.
const Ch* Peek4() const {
return Tell() + 4 <= size_ ? src_ : 0;
}
const Ch* src_; //!< Current read position.
const Ch* begin_; //!< Original head of the string.
const Ch* end_; //!< End of stream.
size_t size_; //!< Size of the stream.
};
} // namespace rapidjson
#endif // RAPIDJSON_MEMORYBUFFER_H_
......@@ -3,6 +3,8 @@
#include "rapidjson/filewritestream.h"
#include "rapidjson/encodedstream.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/memorystream.h"
#include "rapidjson/memorybuffer.h"
using namespace rapidjson;
......@@ -55,6 +57,8 @@ protected:
template <typename FileEncoding, typename MemoryEncoding>
void TestEncodedInputStream(const char* filename) {
// Test FileReadStream
{
char buffer[16];
FILE *fp = Open(filename);
ASSERT_TRUE(fp != 0);
......@@ -72,7 +76,28 @@ protected:
fclose(fp);
}
// Test MemoryStream
{
size_t size;
char* data = ReadFile(filename, true, &size);
MemoryStream ms(data, size);
EncodedInputStream<FileEncoding, MemoryStream> eis(ms);
StringStream s(json_);
while (eis.Peek() != '\0') {
unsigned expected, actual;
EXPECT_TRUE(UTF8<>::Decode(s, &expected));
EXPECT_TRUE(MemoryEncoding::Decode(eis, &actual));
EXPECT_EQ(expected, actual);
}
EXPECT_EQ('\0', s.Peek());
free(data);
}
}
void TestAutoUTFInputStream(const char *filename) {
// Test FileReadStream
{
char buffer[16];
FILE *fp = Open(filename);
ASSERT_TRUE(fp != 0);
......@@ -89,8 +114,29 @@ protected:
fclose(fp);
}
// Test MemoryStream
{
size_t size;
char* data = ReadFile(filename, true, &size);
MemoryStream ms(data, size);
AutoUTFInputStream<unsigned, MemoryStream> eis(ms);
StringStream s(json_);
while (eis.Peek() != '\0') {
unsigned expected, actual;
EXPECT_TRUE(UTF8<>::Decode(s, &expected));
EXPECT_TRUE(AutoUTF<unsigned>::Decode(eis, &actual));
EXPECT_EQ(expected, actual);
}
EXPECT_EQ('\0', s.Peek());
free(data);
}
}
template <typename FileEncoding, typename MemoryEncoding>
void TestEncodedOutputStream(const char* expectedFilename, bool putBOM) {
// Test FileWriteStream
{
char filename[L_tmpnam];
TempFilename(filename);
......@@ -109,17 +155,23 @@ protected:
remove(filename);
}
bool CompareFile(char * filename, const char* expectedFilename) {
size_t actualLength, expectedLength;
char* actualBuffer = ReadFile(filename, false, &actualLength);
char* expectedBuffer = ReadFile(expectedFilename, true, &expectedLength);
bool ret = (expectedLength == actualLength) && memcmp(expectedBuffer, actualBuffer, actualLength) == 0;
free(actualBuffer);
free(expectedBuffer);
return ret;
// Test MemoryBuffer
{
MemoryBuffer mb;
EncodedOutputStream<FileEncoding, MemoryBuffer> eos(mb, putBOM);
StringStream s(json_);
while (s.Peek() != '\0') {
bool success = Transcoder<UTF8<>, MemoryEncoding>::Transcode(s, eos);
EXPECT_TRUE(success);
}
eos.Flush();
EXPECT_TRUE(CompareBufferFile(mb.GetBuffer(), mb.GetSize(), expectedFilename));
}
}
void TestAutoUTFOutputStream(UTFType type, bool putBOM, const char *expectedFilename) {
// Test FileWriteStream
{
char filename[L_tmpnam];
TempFilename(filename);
......@@ -138,6 +190,38 @@ protected:
remove(filename);
}
// Test MemoryBuffer
{
MemoryBuffer mb;
AutoUTFOutputStream<unsigned, MemoryBuffer> eos(mb, type, putBOM);
StringStream s(json_);
while (s.Peek() != '\0') {
bool success = Transcoder<UTF8<>, AutoUTF<unsigned> >::Transcode(s, eos);
EXPECT_TRUE(success);
}
eos.Flush();
EXPECT_TRUE(CompareBufferFile(mb.GetBuffer(), mb.GetSize(), expectedFilename));
}
}
bool CompareFile(const char* filename, const char* expectedFilename) {
size_t actualLength, expectedLength;
char* actualBuffer = ReadFile(filename, false, &actualLength);
char* expectedBuffer = ReadFile(expectedFilename, true, &expectedLength);
bool ret = (expectedLength == actualLength) && memcmp(expectedBuffer, actualBuffer, actualLength) == 0;
free(actualBuffer);
free(expectedBuffer);
return ret;
}
bool CompareBufferFile(const char* actualBuffer, size_t actualLength, const char* expectedFilename) {
size_t expectedLength;
char* expectedBuffer = ReadFile(expectedFilename, true, &expectedLength);
bool ret = (expectedLength == actualLength) && memcmp(expectedBuffer, actualBuffer, actualLength) == 0;
free(expectedBuffer);
return ret;
}
char *json_;
size_t length_;
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment