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:
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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++)
|
||||
|
||||
Reference in New Issue
Block a user