Skip to content

Commit bb52776

Browse files
committed
HPCC-32468 Optimize MemoryBuffer::read(int/short/int64)
Signed-off-by: Gavin Halliday <[email protected]>
1 parent e6c9360 commit bb52776

File tree

3 files changed

+64
-28
lines changed

3 files changed

+64
-28
lines changed

system/jlib/jbuff.cpp

+15-19
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,15 @@ MemoryBuffer &MemoryBuffer::appendFile(const char *fileName)
687687
return *this;
688688
}
689689

690+
#define DO_READ_ENDIAN(len, value) \
691+
CHECKREADPOS(len); \
692+
if (swapEndian) \
693+
doCopyRev<len>(value, buffer + readPos); \
694+
else \
695+
memcpy_iflen(value, buffer + readPos, len); \
696+
readPos += len; \
697+
return *this;
698+
690699
MemoryBuffer & MemoryBuffer::read(char & value)
691700
{
692701
CHECKREADPOS(sizeof(value));
@@ -761,44 +770,32 @@ MemoryBuffer & MemoryBuffer::read(float & value)
761770

762771
MemoryBuffer & MemoryBuffer::read(short & value)
763772
{
764-
return readEndian(sizeof(value), &value);
773+
DO_READ_ENDIAN(sizeof(value), &value);
765774
}
766775

767776
MemoryBuffer & MemoryBuffer::read(unsigned short & value)
768777
{
769-
return readEndian(sizeof(value), &value);
778+
DO_READ_ENDIAN(sizeof(value), &value);
770779
}
771780

772781
MemoryBuffer & MemoryBuffer::read(int & value)
773782
{
774-
return readEndian(sizeof(value), &value);
783+
DO_READ_ENDIAN(sizeof(value), &value);
775784
}
776785

777786
MemoryBuffer & MemoryBuffer::read(unsigned & value)
778787
{
779-
return readEndian(sizeof(value), &value);
788+
DO_READ_ENDIAN(sizeof(value), &value);
780789
}
781790

782-
#if 0
783-
MemoryBuffer & MemoryBuffer::read(unsigned long & value)
784-
{
785-
return readEndian(sizeof(value), &value);
786-
}
787-
788-
MemoryBuffer & MemoryBuffer::read(long & value)
789-
{
790-
return readEndian(sizeof(value), &value);
791-
}
792-
#endif
793-
794791
MemoryBuffer & MemoryBuffer::read(unsigned __int64 & value)
795792
{
796-
return readEndian(sizeof(value), &value);
793+
DO_READ_ENDIAN(sizeof(value), &value);
797794
}
798795

799796
MemoryBuffer & MemoryBuffer::read(__int64 & value)
800797
{
801-
return readEndian(sizeof(value), &value);
798+
DO_READ_ENDIAN(sizeof(value), &value);
802799
}
803800

804801
const byte * MemoryBuffer::readDirect(size32_t len)
@@ -861,7 +858,6 @@ void MemoryBuffer::writeEndianDirect(size32_t pos,size32_t len,const void *buf)
861858
memcpy_iflen(buffer+pos,buf,len);
862859
}
863860

864-
865861
MemoryBuffer & MemoryBuffer::readEndian(size32_t len, void * value)
866862
{
867863
CHECKREADPOS(len);

system/jlib/jbuff.hpp

-1
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,6 @@ class jlib_decl MemoryBuffer
214214
inline const char * toByteArray() const { return curLen ? buffer : nullptr; }
215215
inline const byte * bytes() const { return curLen ? (const byte *)buffer : nullptr; }
216216

217-
218217
private:
219218
MemoryBuffer & read(unsigned long & value); // unimplemented
220219
MemoryBuffer & read(long & value); // unimplemented

system/jlib/jmisc.hpp

+49-8
Original file line numberDiff line numberDiff line change
@@ -120,16 +120,28 @@ extern jlib_decl void _rev(size32_t len, void * ptr);
120120
#endif
121121

122122
inline void _cpyrev2(void * _tgt, const void * _src) {
123-
char * tgt = (char *)_tgt; const char * src = (const char *)_src;
124-
tgt[1]=src[0]; tgt[0] = src[1];
123+
//Technically undefined behaviour because the _src is likely to be a byte stream
124+
//but this will work on all known architectures
125+
unsigned value = *(const unsigned short *)_src;
126+
//NOTE: Optimized by the compiler
127+
value = ((value & 0xFF00) >> 8) |
128+
((value & 0x00FF) << 8);
129+
*(unsigned short *)_tgt = value;
125130
}
126131
inline void _cpyrev3(void * _tgt, const void * _src) {
127132
char * tgt = (char *)_tgt; const char * src = (const char *)_src;
128133
tgt[2] = src[0]; tgt[1]=src[1]; tgt[0] = src[2];
129134
}
130-
inline void _cpyrev4(void * _tgt, const void * _src) {
131-
char * tgt = (char *)_tgt; const char * src = (const char *)_src;
132-
tgt[3]=src[0]; tgt[2] = src[1]; tgt[1]=src[2]; tgt[0] = src[3];
135+
inline void _cpyrev4(void * _tgt, const void * _src) {
136+
//Technically undefined behaviour because the _src is likely to be a byte stream
137+
//but this will work on all known architectures
138+
unsigned value = *(const unsigned *)_src;
139+
//NOTE: The compiler spots this pattern an optimizes it into a byte-swap operation
140+
value = ((value & 0xFF000000) >> 24) |
141+
((value & 0x00FF0000) >> 8) |
142+
((value & 0x0000FF00) << 8) |
143+
((value & 0x000000FF) << 24);
144+
*(unsigned *)_tgt = value;
133145
}
134146
inline void _cpyrev5(void * _tgt, const void * _src) {
135147
char * tgt = (char *)_tgt; const char * src = (const char *)_src;
@@ -147,9 +159,19 @@ inline void _cpyrev7(void * _tgt, const void * _src) {
147159
tgt[3] = src[3]; tgt[2]=src[4]; tgt[1]=src[5]; tgt[0]=src[6];
148160
}
149161
inline void _cpyrev8(void * _tgt, const void * _src) {
150-
char * tgt = (char *)_tgt; const char * src = (const char *)_src;
151-
tgt[7]=src[0]; tgt[6] = src[1]; tgt[5]=src[2]; tgt[4] = src[3];
152-
tgt[3]=src[4]; tgt[2] = src[5]; tgt[1]=src[6]; tgt[0] = src[7];
162+
//Technically undefined behaviour because the _src is likely to be a byte stream
163+
//but this will work on all known architectures
164+
unsigned __int64 value = *(const unsigned __int64 *)_src;
165+
//NOTE: The compiler spots this pattern an optimizes it into a byte-swap operation
166+
value = ((value & 0xFF00000000000000ULL) >> 56) |
167+
((value & 0x00FF000000000000ULL) >> 40) |
168+
((value & 0x0000FF0000000000ULL) >> 24) |
169+
((value & 0x000000FF00000000ULL) >> 8) |
170+
((value & 0x00000000FF000000ULL) << 8) |
171+
((value & 0x0000000000FF0000ULL) << 24) |
172+
((value & 0x000000000000FF00ULL) << 40) |
173+
((value & 0x00000000000000FFULL) << 56);
174+
*(unsigned __int64 *)_tgt = value;
153175
}
154176
inline void _cpyrevn(void * _tgt, const void * _src, unsigned len) {
155177
char * tgt = (char *)_tgt; const char * src = (const char *)_src+len;
@@ -158,6 +180,25 @@ inline void _cpyrevn(void * _tgt, const void * _src, unsigned len) {
158180
}
159181
}
160182

183+
//Define a template class to allow the common byte reversal operations to be optimized
184+
template <unsigned LEN>
185+
inline void doCopyRev(void * tgt, const void * src) {
186+
_cpyrevn(tgt, src, LEN);
187+
}
188+
189+
template <>
190+
inline void doCopyRev<2>(void * tgt, const void * src) {
191+
_cpyrev2(tgt, src);
192+
}
193+
template <>
194+
inline void doCopyRev<4>(void * tgt, const void * src) {
195+
_cpyrev4(tgt, src);
196+
}
197+
template <>
198+
inline void doCopyRev<8>(void * tgt, const void * src) {
199+
_cpyrev8(tgt, src);
200+
}
201+
161202
#if __BYTE_ORDER == __LITTLE_ENDIAN
162203
#define _WINCPYREV(x, y, len) _cpyrevn(x, y, len)
163204
#define _WINCPYREV2(x, y) _cpyrev2(x, y)

0 commit comments

Comments
 (0)