From 34ba390a0daf00ea53dd392edd411ed5d92beef2 Mon Sep 17 00:00:00 2001 From: janwas Date: Fri, 29 Apr 2011 22:55:35 +0000 Subject: [PATCH] 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. --- source/lib/allocators/unique_range.h | 26 ++++++------ source/lib/code_annotation.h | 55 ++++++++++++++++++------- source/lib/file/archive/archive_zip.cpp | 12 +++--- source/lib/file/archive/stream.h | 20 +++++++++ source/lib/file/io/io.cpp | 2 +- source/lib/file/io/io.h | 24 ++++++----- 6 files changed, 93 insertions(+), 46 deletions(-) diff --git a/source/lib/allocators/unique_range.h b/source/lib/allocators/unique_range.h index 51f4cb7129..45859a69d3 100644 --- a/source/lib/allocators/unique_range.h +++ b/source/lib/allocators/unique_range.h @@ -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)); } diff --git a/source/lib/code_annotation.h b/source/lib/code_annotation.h index e1feb5800c..ed63126b64 100644 --- a/source/lib/code_annotation.h +++ b/source/lib/code_annotation.h @@ -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 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 -static inline RValue ToRValue(const T& t) +static inline RValue ToRValue(T& lvalue) { - return RValue((T&)t); + return RValue(lvalue); } -// from lvalue template -static inline RValue ToRValue(T& t) +static inline RValue ToRValue(const T& lvalue) { - return RValue(t); + return RValue((T&)lvalue); } -#define RVREF(T) const RValue& // the type of an rvalue reference +template +static inline RValue ToRValue(const RValue& rvalue) +{ + return RValue(rvalue.LValue()); +} + +#undef RVALUE_REF +#undef LVALUE +#undef RVALUE + +#define RVALUE_REF(T) const RValue& #define LVALUE(rvalue) rvalue.LValue() #define RVALUE(lvalue) ToRValue(lvalue) -#define RVALUE_FROM_R(rvalue) rvalue #endif // #if !HAVE_CPP0X diff --git a/source/lib/file/archive/archive_zip.cpp b/source/lib/file/archive/archive_zip.cpp index 4fac70f202..ca7fa47cb1 100644 --- a/source/lib/file/archive/archive_zip.cpp +++ b/source/lib/file/archive/archive_zip.cpp @@ -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(); diff --git a/source/lib/file/archive/stream.h b/source/lib/file/archive/stream.h index 8b6f923bb8..0ef4d1aefa 100644 --- a/source/lib/file/archive/stream.h +++ b/source/lib/file/archive/stream.h @@ -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 diff --git a/source/lib/file/io/io.cpp b/source/lib/file/io/io.cpp index 5ebc9ac10f..ebd1710502 100644 --- a/source/lib/file/io/io.cpp +++ b/source/lib/file/io/io.cpp @@ -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)); } diff --git a/source/lib/file/io/io.h b/source/lib/file/io/io.h index 0350e1908d..b808c412de 100644 --- a/source/lib/file/io/io.h +++ b/source/lib/file/io/io.h @@ -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++)