1
0
forked from mirrors/0ad

build fix for pre-C++0x compilers.

archive_zip, stream: work around possibly missing support for
std/tr1::bind in GCC by defining a functor manually
also renamed RVREF to RVALUE_REF and ensured RVALUE can convert from
both lvalue and rvalue.
io: avoid dodgy constants and possible overflow by using blockSize=0 to
indicate "don't split"

This was SVN commit r9352.
This commit is contained in:
janwas
2011-04-29 22:55:35 +00:00
parent 1139124451
commit 34ba390a0d
6 changed files with 93 additions and 46 deletions
+13 -13
View File
@@ -68,23 +68,23 @@ public:
Set(p, size, deleter);
}
UniqueRange(RVREF(UniqueRange) rvref)
UniqueRange(RVALUE_REF(UniqueRange) rvalue)
{
UniqueRange& rhs = LVALUE(rvref);
address_ = rhs.address_;
size_ = rhs.size_;
rhs.address_ = 0;
UniqueRange& lvalue = LVALUE(rvalue);
address_ = lvalue.address_;
size_ = lvalue.size_;
lvalue.address_ = 0;
}
UniqueRange& operator=(RVREF(UniqueRange) rvref)
UniqueRange& operator=(RVALUE_REF(UniqueRange) rvalue)
{
UniqueRange& rhs = LVALUE(rvref);
if(this != &rhs)
UniqueRange& lvalue = LVALUE(rvalue);
if(this != &lvalue)
{
Delete();
address_ = rhs.address_;
size_ = rhs.size_;
rhs.address_ = 0;
address_ = lvalue.address_;
size_ = lvalue.size_;
lvalue.address_ = 0;
}
return *this;
}
@@ -170,12 +170,12 @@ static inline void swap(UniqueRange& p1, UniqueRange& p2)
p1.swap(p2);
}
static inline void swap(RVREF(UniqueRange) p1, UniqueRange& p2)
static inline void swap(RVALUE_REF(UniqueRange) p1, UniqueRange& p2)
{
p2.swap(LVALUE(p1));
}
static inline void swap(UniqueRange& p1, RVREF(UniqueRange) p2)
static inline void swap(UniqueRange& p1, RVALUE_REF(UniqueRange) p2)
{
p1.swap(LVALUE(p2));
}
+39 -16
View File
@@ -330,19 +330,30 @@ private:\
//-----------------------------------------------------------------------------
// partial emulation of C++0x rvalue references (required for UniqueRange)
// C++0x rvalue references (required for UniqueRange)
#if HAVE_CPP0X
/**
* expands to the type `rvalue reference to T'; used in function
* parameter declarations. for example, UniqueRange's move ctor is:
* UniqueRange(RVALUE_REF(UniqueRange) rvalue) { ... }
**/
#define RVALUE_REF(T) T&&
#define RVREF(T) T&& // the type of an rvalue reference
#define LVALUE(rvalue) rvalue // (a named rvalue reference is an lvalue)
/**
* convert an rvalue to an lvalue
**/
#define LVALUE(rvalue) rvalue // in C++0x, a named rvalue reference is already an lvalue
/**
* convert anything (lvalue or rvalue) to an rvalue
**/
#define RVALUE(lvalue) std::move(lvalue)
#define RVALUE_FROM_R(rvalue) RVALUE(rvalue) // (see above)
#else
// RVALUE wraps an lvalue reference in this class for later use by a
// "move ctor" that takes an RValue.
#if !HAVE_CPP0X // partial emulation
// lvalue references are wrapped in this class, which is the
// actual argument passed to the "move ctor" etc.
template<typename T>
class RValue
{
@@ -351,27 +362,39 @@ public:
T& LValue() const { return lvalue; }
private:
// (avoid "assignment operator could not be generated" warning)
const RValue& operator=(const RValue&);
T& lvalue;
};
// from rvalue or const lvalue
// (to deduce T automatically, we need function templates)
template<class T>
static inline RValue<T> ToRValue(const T& t)
static inline RValue<T> ToRValue(T& lvalue)
{
return RValue<T>((T&)t);
return RValue<T>(lvalue);
}
// from lvalue
template<class T>
static inline RValue<T> ToRValue(T& t)
static inline RValue<T> ToRValue(const T& lvalue)
{
return RValue<T>(t);
return RValue<T>((T&)lvalue);
}
#define RVREF(T) const RValue<T>& // the type of an rvalue reference
template<class T>
static inline RValue<T> ToRValue(const RValue<T>& rvalue)
{
return RValue<T>(rvalue.LValue());
}
#undef RVALUE_REF
#undef LVALUE
#undef RVALUE
#define RVALUE_REF(T) const RValue<T>&
#define LVALUE(rvalue) rvalue.LValue()
#define RVALUE(lvalue) ToRValue(lvalue)
#define RVALUE_FROM_R(rvalue) rvalue
#endif // #if !HAVE_CPP0X
+7 -5
View File
@@ -334,7 +334,8 @@ public:
Stream stream(codec);
stream.SetOutputBuffer(buf.get(), size);
io::Operation op(*m_file.get(), 0, m_csize, m_ofs);
RETURN_ERR(io::Run(op, io::Parameters(), std::bind(&Stream::Feed, &stream, std::placeholders::_1, std::placeholders::_2)));
StreamFeeder streamFeeder(stream);
RETURN_ERR(io::Run(op, io::Parameters(), streamFeeder));
RETURN_ERR(stream.Finish());
#if CODEC_COMPUTE_CHECKSUM
debug_assert(m_checksum == stream.Checksum());
@@ -447,7 +448,7 @@ public:
size_t cd_numEntries = 0;
size_t cd_size = 0;
RETURN_ERR(LocateCentralDirectory(m_file, m_fileSize, cd_ofs, cd_numEntries, cd_size));
UniqueRange buf(io::Allocate(cd_size));
UniqueRange buf(RVALUE(io::Allocate(cd_size)));
io::Operation op(*m_file.get(), buf.get(), cd_size, cd_ofs);
RETURN_ERR(io::Run(op));
@@ -532,7 +533,7 @@ private:
static LibError LocateCentralDirectory(const PFile& file, off_t fileSize, off_t& cd_ofs, size_t& cd_numEntries, size_t& cd_size)
{
const size_t maxScanSize = 66000u; // see below
UniqueRange buf(io::Allocate(maxScanSize));
UniqueRange buf(RVALUE(io::Allocate(maxScanSize)));
// expected case: ECDR at EOF; no file comment
LibError ret = ScanForEcdr(file, fileSize, (u8*)buf.get(), sizeof(ECDR), cd_numEntries, cd_ofs, cd_size);
@@ -638,7 +639,7 @@ public:
// allocate memory
const size_t csizeMax = codec->MaxOutputSize(size_t(usize));
UniqueRange buf(io::Allocate(sizeof(LFH) + pathnameLength + csizeMax));
UniqueRange buf(RVALUE(io::Allocate(sizeof(LFH) + pathnameLength + csizeMax)));
// read and compress file contents
size_t csize; u32 checksum;
@@ -647,7 +648,8 @@ public:
Stream stream(codec);
stream.SetOutputBuffer(cdata, csizeMax);
io::Operation op(*file.get(), 0, usize);
RETURN_ERR(io::Run(op, io::Parameters(), std::bind(&Stream::Feed, &stream, std::placeholders::_1, std::placeholders::_2)));
StreamFeeder streamFeeder(stream);
RETURN_ERR(io::Run(op, io::Parameters(), streamFeeder));
RETURN_ERR(stream.Finish());
csize = stream.OutSize();
checksum = stream.Checksum();
+20
View File
@@ -110,4 +110,24 @@ private:
u32 m_checksum;
};
// avoids the need for std::bind (not supported on all compilers) and boost::bind (can't be
// used at work)
struct StreamFeeder
{
NONCOPYABLE(StreamFeeder);
public:
StreamFeeder(Stream& stream)
: stream(stream)
{
}
LibError operator()(const u8* data, size_t size) const
{
return stream.Feed(data, size);
}
private:
Stream& stream;
};
#endif // #ifndef INCLUDED_STREAM
+1 -1
View File
@@ -74,7 +74,7 @@ UniqueRange Allocate(size_t size, size_t alignment)
const size_t alignedSize = round_up(size, alignment);
const UniqueRange::pointer p = rtl_AllocateAligned(alignedSize, alignment);
return UniqueRange(p, size, idxDeleterAligned);
return RVALUE(UniqueRange(p, size, idxDeleterAligned));
}
+13 -11
View File
@@ -45,6 +45,8 @@ namespace io {
// @return memory suitable for use as an I/O buffer (address is a
// multiple of alignment, size is rounded up to a multiple of alignment)
// @param alignment is automatically increased if smaller than the
// UniqueRange requirement.
//
// use this instead of the file cache for write buffers that are
// never reused (avoids displacing other items).
@@ -58,7 +60,8 @@ LIB_API UniqueRange Allocate(size_t size, size_t alignment = maxSectorSize);
struct Operation
{
// @param buf can be 0, in which case temporary block buffers are allocated.
// otherwise, it must be padded to the I/O alignment, e.g. via io::Allocate.
// otherwise, it must be aligned and padded to the I/O alignment, e.g. via
// io::Allocate.
Operation(const File& file, void* buf, off_t size, off_t offset = 0)
: fd(file.Descriptor()), opcode(file.Opcode())
, offset(offset), size(size), buf((void*)buf)
@@ -90,10 +93,7 @@ struct Parameters
// default to single blocking I/Os
Parameters()
: alignment(1) // no alignment requirements
// use one huge "block" truncated to the requested size.
// (this value is a power of two as required by Validate and
// avoids overflowing off_t in DivideRoundUp)
, blockSize((SIZE_MAX/2)+1)
, blockSize(0) // do not split into blocks
, queueDepth(1) // disable aio
{
}
@@ -115,8 +115,11 @@ struct Parameters
debug_assert(is_pow2(alignment));
debug_assert(alignment > 0);
debug_assert(is_pow2(blockSize));
debug_assert(pageSize <= blockSize); // no upper limit needed
if(blockSize != 0)
{
debug_assert(is_pow2(blockSize));
debug_assert(pageSize <= blockSize); // (don't bother checking an upper bound)
}
debug_assert(1 <= queueDepth && queueDepth <= maxQueueDepth);
@@ -130,7 +133,7 @@ struct Parameters
off_t alignment;
size_t blockSize;
size_t blockSize; // 0 for one big "block"
size_t queueDepth;
};
@@ -182,8 +185,7 @@ public:
ControlBlockRingBuffer(const Operation& op, const Parameters& p)
: controlBlocks() // zero-initialize
{
// (default p.blockSize is "infinity", so clamp to the total size)
const size_t blockSize = (size_t)std::min((off_t)p.blockSize, op.size);
const size_t blockSize = p.blockSize? p.blockSize : (size_t)op.size;
const bool temporaryBuffersRequested = (op.buf == 0);
if(temporaryBuffersRequested)
@@ -230,7 +232,7 @@ static inline LibError Run(const Operation& op, const Parameters& p = Parameters
ControlBlockRingBuffer controlBlockRingBuffer(op, p);
const off_t numBlocks = DivideRoundUp(op.size, (off_t)p.blockSize);
const off_t numBlocks = p.blockSize? (off_t)DivideRoundUp((u64)op.size, (u64)p.blockSize) : 1;
for(off_t blocksIssued = 0, blocksCompleted = 0; blocksCompleted < numBlocks; blocksCompleted++)
{
for(; blocksIssued != numBlocks && blocksIssued < blocksCompleted + (off_t)p.queueDepth; blocksIssued++)