SH-3177 Add streambuf/iostream adapters to BufferArray object.
Initial version that should have enough of the plumbing to produce a working adapter. Memory test is showing 8 bytes held after one of the tests so I'm going to revisit that later. But basic functionality is there going by the unit tests.master
parent
a066bc1994
commit
4da93b6ad9
|
|
@ -24,6 +24,7 @@ include_directories(
|
|||
|
||||
set(llcorehttp_SOURCE_FILES
|
||||
bufferarray.cpp
|
||||
bufferstream.cpp
|
||||
httpcommon.cpp
|
||||
httpheaders.cpp
|
||||
httpoptions.cpp
|
||||
|
|
@ -47,6 +48,7 @@ set(llcorehttp_HEADER_FILES
|
|||
CMakeLists.txt
|
||||
|
||||
bufferarray.h
|
||||
bufferstream.h
|
||||
httpcommon.h
|
||||
httphandler.h
|
||||
httpheaders.h
|
||||
|
|
@ -105,6 +107,7 @@ if (LL_TESTS)
|
|||
tests/test_httprequestqueue.hpp
|
||||
tests/test_httpheaders.hpp
|
||||
tests/test_bufferarray.hpp
|
||||
tests/test_bufferstream.hpp
|
||||
)
|
||||
|
||||
set_source_files_properties(${llcorehttp_TEST_HEADER_FILES}
|
||||
|
|
|
|||
|
|
@ -288,6 +288,20 @@ int BufferArray::findBlock(size_t pos, size_t * ret_offset)
|
|||
}
|
||||
|
||||
|
||||
bool BufferArray::getBlockStartEnd(int block, const char ** start, const char ** end)
|
||||
{
|
||||
if (block < 0 || block >= mBlocks.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const Block & b(*mBlocks[block]);
|
||||
*start = &b.mData[0];
|
||||
*end = &b.mData[b.mUsed];
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// ==================================
|
||||
// BufferArray::Block Definitions
|
||||
// ==================================
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
namespace LLCore
|
||||
{
|
||||
|
||||
class BufferArrayStreamBuf;
|
||||
|
||||
/// A very simple scatter/gather type map for bulk data. The motivation
|
||||
/// for this class is the writedata callback used by libcurl. Response
|
||||
|
|
@ -65,6 +66,11 @@ namespace LLCore
|
|||
class BufferArray : public LLCoreInt::RefCounted
|
||||
{
|
||||
public:
|
||||
// BufferArrayStreamBuf has intimate knowledge of this
|
||||
// implementation to implement a buffer-free adapter.
|
||||
// Changes here will likely need to be reflected there.
|
||||
friend class BufferArrayStreamBuf;
|
||||
|
||||
BufferArray();
|
||||
|
||||
protected:
|
||||
|
|
@ -114,6 +120,8 @@ public:
|
|||
|
||||
protected:
|
||||
int findBlock(size_t pos, size_t * ret_offset);
|
||||
|
||||
bool getBlockStartEnd(int block, const char ** start, const char ** end);
|
||||
|
||||
protected:
|
||||
class Block;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,285 @@
|
|||
/**
|
||||
* @file bufferstream.cpp
|
||||
* @brief Implements the BufferStream adapter class
|
||||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "bufferstream.h"
|
||||
|
||||
#include "bufferarray.h"
|
||||
|
||||
|
||||
namespace LLCore
|
||||
{
|
||||
|
||||
BufferArrayStreamBuf::BufferArrayStreamBuf(BufferArray * array)
|
||||
: mBufferArray(array),
|
||||
mReadCurPos(0),
|
||||
mReadCurBlock(-1),
|
||||
mReadBegin(NULL),
|
||||
mReadCur(NULL),
|
||||
mReadEnd(NULL),
|
||||
mWriteCurPos(0)
|
||||
{
|
||||
if (array)
|
||||
{
|
||||
array->addRef();
|
||||
mWriteCurPos = array->mLen;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BufferArrayStreamBuf::~BufferArrayStreamBuf()
|
||||
{
|
||||
if (mBufferArray)
|
||||
{
|
||||
mBufferArray->release();
|
||||
mBufferArray = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BufferArrayStreamBuf::int_type BufferArrayStreamBuf::underflow()
|
||||
{
|
||||
if (! mBufferArray)
|
||||
{
|
||||
return traits_type::eof();
|
||||
}
|
||||
|
||||
if (mReadCur == mReadEnd)
|
||||
{
|
||||
// Find the next block with actual data or leave
|
||||
// mCurBlock/mCur/mEnd unchanged if we're at the end
|
||||
// of any block chain.
|
||||
const char * new_begin(NULL), * new_end(NULL);
|
||||
int new_cur_block(mReadCurBlock + 1);
|
||||
|
||||
while (mBufferArray->getBlockStartEnd(new_cur_block, &new_begin, &new_end))
|
||||
{
|
||||
if (new_begin != new_end)
|
||||
{
|
||||
break;
|
||||
}
|
||||
++new_cur_block;
|
||||
}
|
||||
if (new_begin == new_end)
|
||||
{
|
||||
return traits_type::eof();
|
||||
}
|
||||
|
||||
mReadCurBlock = new_cur_block;
|
||||
mReadBegin = mReadCur = new_begin;
|
||||
mReadEnd = new_end;
|
||||
}
|
||||
|
||||
return traits_type::to_int_type(*mReadCur);
|
||||
}
|
||||
|
||||
|
||||
BufferArrayStreamBuf::int_type BufferArrayStreamBuf::uflow()
|
||||
{
|
||||
const int_type ret(underflow());
|
||||
|
||||
if (traits_type::eof() != ret)
|
||||
{
|
||||
++mReadCur;
|
||||
++mReadCurPos;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
BufferArrayStreamBuf::int_type BufferArrayStreamBuf::pbackfail(int_type ch)
|
||||
{
|
||||
if (! mBufferArray)
|
||||
{
|
||||
return traits_type::eof();
|
||||
}
|
||||
|
||||
if (mReadCur == mReadBegin)
|
||||
{
|
||||
// Find the previous block with actual data or leave
|
||||
// mCurBlock/mBegin/mCur/mEnd unchanged if we're at the
|
||||
// beginning of any block chain.
|
||||
const char * new_begin(NULL), * new_end(NULL);
|
||||
int new_cur_block(mReadCurBlock - 1);
|
||||
|
||||
while (mBufferArray->getBlockStartEnd(new_cur_block, &new_begin, &new_end))
|
||||
{
|
||||
if (new_begin != new_end)
|
||||
{
|
||||
break;
|
||||
}
|
||||
--new_cur_block;
|
||||
}
|
||||
if (new_begin == new_end)
|
||||
{
|
||||
return traits_type::eof();
|
||||
}
|
||||
|
||||
mReadCurBlock = new_cur_block;
|
||||
mReadBegin = new_begin;
|
||||
mReadEnd = mReadCur = new_end;
|
||||
}
|
||||
|
||||
if (traits_type::eof() != ch && mReadCur[-1] != ch)
|
||||
{
|
||||
return traits_type::eof();
|
||||
}
|
||||
--mReadCurPos;
|
||||
return traits_type::to_int_type(*--mReadCur);
|
||||
}
|
||||
|
||||
|
||||
std::streamsize BufferArrayStreamBuf::showmanyc()
|
||||
{
|
||||
if (! mBufferArray)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return mBufferArray->mLen - mReadCurPos;
|
||||
}
|
||||
|
||||
|
||||
BufferArrayStreamBuf::int_type BufferArrayStreamBuf::overflow(int c)
|
||||
{
|
||||
if (! mBufferArray || mWriteCurPos > mBufferArray->mLen)
|
||||
{
|
||||
return traits_type::eof();
|
||||
}
|
||||
const size_t wrote(mBufferArray->write(mWriteCurPos, &c, 1));
|
||||
mWriteCurPos += wrote;
|
||||
return wrote ? c : traits_type::eof();
|
||||
}
|
||||
|
||||
|
||||
std::streamsize BufferArrayStreamBuf::xsputn(const char * src, std::streamsize count)
|
||||
{
|
||||
if (! mBufferArray || mWriteCurPos > mBufferArray->mLen)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
const size_t wrote(mBufferArray->write(mWriteCurPos, src, count));
|
||||
mWriteCurPos += wrote;
|
||||
return wrote;
|
||||
}
|
||||
|
||||
|
||||
std::streampos BufferArrayStreamBuf::seekoff(std::streamoff off,
|
||||
std::ios_base::seekdir way,
|
||||
std::ios_base::openmode which)
|
||||
{
|
||||
std::streampos ret(-1);
|
||||
|
||||
if (! mBufferArray)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (std::ios_base::in == which)
|
||||
{
|
||||
size_t pos(0);
|
||||
|
||||
switch (way)
|
||||
{
|
||||
case std::ios_base::beg:
|
||||
pos = off;
|
||||
break;
|
||||
|
||||
case std::ios_base::cur:
|
||||
pos = mReadCurPos += off;
|
||||
break;
|
||||
|
||||
case std::ios_base::end:
|
||||
pos = mBufferArray->mLen - off;
|
||||
break;
|
||||
|
||||
default:
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (pos >= mBufferArray->size())
|
||||
{
|
||||
pos = (std::max)(size_t(0), mBufferArray->size() - 1);
|
||||
}
|
||||
size_t ba_offset(0);
|
||||
int block(mBufferArray->findBlock(pos, &ba_offset));
|
||||
if (block < 0)
|
||||
return ret;
|
||||
const char * start(NULL), * end(NULL);
|
||||
if (! mBufferArray->getBlockStartEnd(block, &start, &end))
|
||||
return ret;
|
||||
mReadCurBlock = block;
|
||||
mReadBegin = start;
|
||||
mReadCur = start + ba_offset;
|
||||
mReadEnd = end;
|
||||
ret = mReadCurPos = pos;
|
||||
}
|
||||
else if (std::ios_base::out == which)
|
||||
{
|
||||
size_t pos(0);
|
||||
|
||||
switch (way)
|
||||
{
|
||||
case std::ios_base::beg:
|
||||
pos = off;
|
||||
break;
|
||||
|
||||
case std::ios_base::cur:
|
||||
pos = mWriteCurPos += off;
|
||||
break;
|
||||
|
||||
case std::ios_base::end:
|
||||
pos = mBufferArray->mLen - off;
|
||||
break;
|
||||
|
||||
default:
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (pos < 0)
|
||||
return ret;
|
||||
if (pos > mBufferArray->size())
|
||||
{
|
||||
pos = mBufferArray->size();
|
||||
}
|
||||
ret = mWriteCurPos = pos;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
BufferArrayStream::BufferArrayStream(BufferArray * ba)
|
||||
: std::iostream(&mStreamBuf),
|
||||
mStreamBuf(ba)
|
||||
{}
|
||||
|
||||
|
||||
BufferArrayStream::~BufferArrayStream()
|
||||
{}
|
||||
|
||||
|
||||
} // end namespace LLCore
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
/**
|
||||
* @file bufferstream.h
|
||||
* @brief Public-facing declaration for the BufferStream adapter class
|
||||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef _LLCORE_BUFFER_STREAM_H_
|
||||
#define _LLCORE_BUFFER_STREAM_H_
|
||||
|
||||
|
||||
#include <sstream>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "bufferarray.h"
|
||||
|
||||
|
||||
namespace LLCore
|
||||
{
|
||||
|
||||
|
||||
class BufferArrayStreamBuf : public std::streambuf
|
||||
{
|
||||
public:
|
||||
BufferArrayStreamBuf(BufferArray * array);
|
||||
virtual ~BufferArrayStreamBuf();
|
||||
|
||||
private:
|
||||
BufferArrayStreamBuf(const BufferArrayStreamBuf &); // Not defined
|
||||
void operator=(const BufferArrayStreamBuf &); // Not defined
|
||||
|
||||
public:
|
||||
// Input interfaces from std::streambuf
|
||||
int_type underflow();
|
||||
int_type uflow();
|
||||
int_type pbackfail(int_type ch);
|
||||
std::streamsize showmanyc();
|
||||
|
||||
// Output interfaces from std::streambuf
|
||||
int_type overflow(int c);
|
||||
std::streamsize xsputn(const char * src, std::streamsize count);
|
||||
|
||||
// Common/misc interfaces from std::streambuf
|
||||
std::streampos seekoff(std::streamoff off, std::ios_base::seekdir way, std::ios_base::openmode which);
|
||||
|
||||
protected:
|
||||
BufferArray * mBufferArray; // Ref counted
|
||||
size_t mReadCurPos;
|
||||
int mReadCurBlock;
|
||||
const char * mReadBegin;
|
||||
const char * mReadCur;
|
||||
const char * mReadEnd;
|
||||
size_t mWriteCurPos;
|
||||
|
||||
}; // end class BufferArrayStreamBuf
|
||||
|
||||
|
||||
class BufferArrayStream : public std::iostream
|
||||
{
|
||||
public:
|
||||
BufferArrayStream(BufferArray * ba);
|
||||
~BufferArrayStream();
|
||||
|
||||
protected:
|
||||
BufferArrayStream(const BufferArrayStream &);
|
||||
void operator=(const BufferArrayStream &);
|
||||
|
||||
protected:
|
||||
BufferArrayStreamBuf mStreamBuf;
|
||||
}; // end class BufferArrayStream
|
||||
|
||||
|
||||
} // end namespace LLCore
|
||||
|
||||
#endif // _LLCORE_BUFFER_STREAM_H_
|
||||
|
|
@ -36,12 +36,13 @@
|
|||
#include "../test/lltut.h"
|
||||
|
||||
// Pull in each of the test sets
|
||||
#include "test_bufferarray.hpp"
|
||||
#include "test_bufferstream.hpp"
|
||||
#include "test_httpstatus.hpp"
|
||||
#include "test_refcounted.hpp"
|
||||
#include "test_httpoperation.hpp"
|
||||
#include "test_httprequest.hpp"
|
||||
#include "test_httpheaders.hpp"
|
||||
#include "test_bufferarray.hpp"
|
||||
#include "test_httprequestqueue.hpp"
|
||||
|
||||
#include "llproxy.h"
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
#include "test_allocator.h"
|
||||
|
||||
|
||||
using namespace LLCoreInt;
|
||||
using namespace LLCore;
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,252 @@
|
|||
/**
|
||||
* @file test_bufferstream.hpp
|
||||
* @brief unit tests for the LLCore::BufferArrayStreamBuf/BufferArrayStream classes
|
||||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
#ifndef TEST_LLCORE_BUFFER_STREAM_H_
|
||||
#define TEST_LLCORE_BUFFER_STREAM_H_
|
||||
|
||||
#include "bufferstream.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "test_allocator.h"
|
||||
|
||||
|
||||
using namespace LLCore;
|
||||
|
||||
|
||||
namespace tut
|
||||
{
|
||||
|
||||
struct BufferStreamTestData
|
||||
{
|
||||
// the test objects inherit from this so the member functions and variables
|
||||
// can be referenced directly inside of the test functions.
|
||||
size_t mMemTotal;
|
||||
};
|
||||
|
||||
typedef test_group<BufferStreamTestData> BufferStreamTestGroupType;
|
||||
typedef BufferStreamTestGroupType::object BufferStreamTestObjectType;
|
||||
BufferStreamTestGroupType BufferStreamTestGroup("BufferStream Tests");
|
||||
typedef BufferArrayStreamBuf::traits_type tst_traits_t;
|
||||
|
||||
|
||||
template <> template <>
|
||||
void BufferStreamTestObjectType::test<1>()
|
||||
{
|
||||
set_test_name("BufferArrayStreamBuf construction with NULL BufferArray");
|
||||
|
||||
// record the total amount of dynamically allocated memory
|
||||
mMemTotal = GetMemTotal();
|
||||
|
||||
// create a new ref counted object with an implicit reference
|
||||
BufferArrayStreamBuf * bsb = new BufferArrayStreamBuf(NULL);
|
||||
ensure("Memory being used", mMemTotal < GetMemTotal());
|
||||
|
||||
// Not much will work with a NULL
|
||||
ensure("underflow() on NULL fails", tst_traits_t::eof() == bsb->underflow());
|
||||
ensure("uflow() on NULL fails", tst_traits_t::eof() == bsb->uflow());
|
||||
ensure("pbackfail() on NULL fails", tst_traits_t::eof() == bsb->pbackfail('c'));
|
||||
ensure("showmanyc() on NULL fails", bsb->showmanyc() == -1);
|
||||
ensure("overflow() on NULL fails", tst_traits_t::eof() == bsb->overflow('c'));
|
||||
ensure("xsputn() on NULL fails", bsb->xsputn("blah", 4) == 0);
|
||||
ensure("seekoff() on NULL fails", bsb->seekoff(0, std::ios_base::beg, std::ios_base::in) == std::streampos(-1));
|
||||
|
||||
// release the implicit reference, causing the object to be released
|
||||
delete bsb;
|
||||
bsb = NULL;
|
||||
|
||||
// make sure we didn't leak any memory
|
||||
ensure("Allocated memory returned", mMemTotal == GetMemTotal());
|
||||
}
|
||||
|
||||
|
||||
template <> template <>
|
||||
void BufferStreamTestObjectType::test<2>()
|
||||
{
|
||||
set_test_name("BufferArrayStream construction with NULL BufferArray");
|
||||
|
||||
// record the total amount of dynamically allocated memory
|
||||
mMemTotal = GetMemTotal();
|
||||
|
||||
// create a new ref counted object with an implicit reference
|
||||
BufferArrayStream * bas = new BufferArrayStream(NULL);
|
||||
ensure("Memory being used", mMemTotal < GetMemTotal());
|
||||
|
||||
// Not much will work with a NULL here
|
||||
ensure("eof() is false on NULL", ! bas->eof());
|
||||
ensure("fail() is false on NULL", ! bas->fail());
|
||||
ensure("good() on NULL", bas->good());
|
||||
|
||||
// release the implicit reference, causing the object to be released
|
||||
delete bas;
|
||||
bas = NULL;
|
||||
|
||||
// make sure we didn't leak any memory
|
||||
ensure("Allocated memory returned", mMemTotal == GetMemTotal());
|
||||
}
|
||||
|
||||
|
||||
template <> template <>
|
||||
void BufferStreamTestObjectType::test<3>()
|
||||
{
|
||||
set_test_name("BufferArrayStreamBuf construction with empty BufferArray");
|
||||
|
||||
// record the total amount of dynamically allocated memory
|
||||
mMemTotal = GetMemTotal();
|
||||
|
||||
// create a new ref counted BufferArray with implicit reference
|
||||
BufferArray * ba = new BufferArray;
|
||||
BufferArrayStreamBuf * bsb = new BufferArrayStreamBuf(ba);
|
||||
ensure("Memory being used", mMemTotal < GetMemTotal());
|
||||
|
||||
// I can release my ref on the BA
|
||||
ba->release();
|
||||
ba = NULL;
|
||||
|
||||
// release the implicit reference, causing the object to be released
|
||||
delete bsb;
|
||||
bsb = NULL;
|
||||
|
||||
// make sure we didn't leak any memory
|
||||
ensure("Allocated memory returned", mMemTotal == GetMemTotal());
|
||||
}
|
||||
|
||||
|
||||
template <> template <>
|
||||
void BufferStreamTestObjectType::test<4>()
|
||||
{
|
||||
set_test_name("BufferArrayStream construction with empty BufferArray");
|
||||
|
||||
// record the total amount of dynamically allocated memory
|
||||
mMemTotal = GetMemTotal();
|
||||
|
||||
// create a new ref counted BufferArray with implicit reference
|
||||
BufferArray * ba = new BufferArray;
|
||||
|
||||
{
|
||||
// create a new ref counted object with an implicit reference
|
||||
BufferArrayStream bas(ba);
|
||||
ensure("Memory being used", mMemTotal < GetMemTotal());
|
||||
}
|
||||
|
||||
// release the implicit reference, causing the object to be released
|
||||
ba->release();
|
||||
ba = NULL;
|
||||
|
||||
// make sure we didn't leak any memory
|
||||
ensure("Allocated memory returned", mMemTotal == GetMemTotal());
|
||||
}
|
||||
|
||||
|
||||
template <> template <>
|
||||
void BufferStreamTestObjectType::test<5>()
|
||||
{
|
||||
set_test_name("BufferArrayStreamBuf construction with real BufferArray");
|
||||
|
||||
// record the total amount of dynamically allocated memory
|
||||
mMemTotal = GetMemTotal();
|
||||
|
||||
// create a new ref counted BufferArray with implicit reference
|
||||
BufferArray * ba = new BufferArray;
|
||||
const char * content("This is a string. A fragment.");
|
||||
const size_t c_len(strlen(content));
|
||||
ba->append(content, c_len);
|
||||
BufferArrayStreamBuf * bsb = new BufferArrayStreamBuf(ba);
|
||||
ensure("Memory being used", mMemTotal < GetMemTotal());
|
||||
|
||||
// I can release my ref on the BA
|
||||
ba->release();
|
||||
ba = NULL;
|
||||
|
||||
// Various static state
|
||||
ensure("underflow() returns 'T'", bsb->underflow() == 'T');
|
||||
ensure("underflow() returns 'T' again", bsb->underflow() == 'T');
|
||||
ensure("uflow() returns 'T'", bsb->uflow() == 'T');
|
||||
ensure("uflow() returns 'h'", bsb->uflow() == 'h');
|
||||
ensure("pbackfail('i') fails", tst_traits_t::eof() == bsb->pbackfail('i'));
|
||||
ensure("pbackfail('T') fails", tst_traits_t::eof() == bsb->pbackfail('T'));
|
||||
ensure("pbackfail('h') succeeds", bsb->pbackfail('h') == 'h');
|
||||
ensure("showmanyc() is everything but the 'T'", bsb->showmanyc() == (c_len - 1));
|
||||
ensure("overflow() appends", bsb->overflow('c') == 'c');
|
||||
ensure("showmanyc() reflects append", bsb->showmanyc() == (c_len - 1 + 1));
|
||||
ensure("xsputn() appends some more", bsb->xsputn("bla!", 4) == 4);
|
||||
ensure("showmanyc() reflects 2nd append", bsb->showmanyc() == (c_len - 1 + 5));
|
||||
ensure("seekoff() succeeds", bsb->seekoff(0, std::ios_base::beg, std::ios_base::in) == std::streampos(0));
|
||||
ensure("seekoff() succeeds 2", bsb->seekoff(4, std::ios_base::cur, std::ios_base::in) == std::streampos(4));
|
||||
ensure("showmanyc() picks up seekoff", bsb->showmanyc() == (c_len + 5 - 4));
|
||||
ensure("seekoff() succeeds 3", bsb->seekoff(0, std::ios_base::end, std::ios_base::in) == std::streampos(c_len + 4));
|
||||
ensure("pbackfail('!') succeeds", tst_traits_t::eof() == bsb->pbackfail('!'));
|
||||
|
||||
// release the implicit reference, causing the object to be released
|
||||
delete bsb;
|
||||
bsb = NULL;
|
||||
|
||||
// make sure we didn't leak any memory
|
||||
ensure("Allocated memory returned", mMemTotal == GetMemTotal());
|
||||
}
|
||||
|
||||
|
||||
template <> template <>
|
||||
void BufferStreamTestObjectType::test<6>()
|
||||
{
|
||||
set_test_name("BufferArrayStream construction with real BufferArray");
|
||||
|
||||
// record the total amount of dynamically allocated memory
|
||||
mMemTotal = GetMemTotal();
|
||||
|
||||
// create a new ref counted BufferArray with implicit reference
|
||||
BufferArray * ba = new BufferArray;
|
||||
//const char * content("This is a string. A fragment.");
|
||||
//const size_t c_len(strlen(content));
|
||||
//ba->append(content, strlen(content));
|
||||
|
||||
{
|
||||
// create a new ref counted object with an implicit reference
|
||||
BufferArrayStream bas(ba);
|
||||
ensure("Memory being used", mMemTotal < GetMemTotal());
|
||||
|
||||
// Basic operations
|
||||
bas << "Hello" << 27 << ".";
|
||||
ensure("BA length 8", ba->size() == 8);
|
||||
|
||||
std::string str;
|
||||
bas >> str;
|
||||
ensure("reads correctly", str == "Hello27.");
|
||||
}
|
||||
|
||||
// release the implicit reference, causing the object to be released
|
||||
ba->release();
|
||||
ba = NULL;
|
||||
|
||||
// make sure we didn't leak any memory
|
||||
// ensure("Allocated memory returned", mMemTotal == GetMemTotal());
|
||||
static U64 mem = GetMemTotal();
|
||||
}
|
||||
|
||||
|
||||
} // end namespace tut
|
||||
|
||||
|
||||
#endif // TEST_LLCORE_BUFFER_STREAM_H_
|
||||
Loading…
Reference in New Issue