From 3f9852bd581a0314f76a21723aaf9afb2f968108 Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Sat, 1 Jan 2011 21:25:23 +0100 Subject: [PATCH] random access byteBuffer --- pvDataApp/misc/byteBuffer.cpp | 145 +++++++++++++++++++++--- pvDataApp/misc/byteBuffer.h | 190 +++++++++++++++++++++++++++++--- testApp/misc/testByteBuffer.cpp | 46 ++++++++ 3 files changed, 349 insertions(+), 32 deletions(-) diff --git a/pvDataApp/misc/byteBuffer.cpp b/pvDataApp/misc/byteBuffer.cpp index 7ee6730..a0a2137 100644 --- a/pvDataApp/misc/byteBuffer.cpp +++ b/pvDataApp/misc/byteBuffer.cpp @@ -22,11 +22,10 @@ namespace epics { _bufferByteOrder(byteOrder), _size(size), _position(0), _limit(size), _buffer(0) { - if (size < 0) - throw EpicsException("negative size"); + if(size<0) throw EpicsException("negative size"); if (byteOrder!=EPICS_ENDIAN_BIG && byteOrder!=EPICS_ENDIAN_LITTLE) - throw EpicsException("invalid endian"); + throw EpicsException("invalid endianness"); _buffer = new char[_size]; } @@ -53,17 +52,25 @@ namespace epics { } bool ByteBuffer::getBoolean() { - if(_position<_limit) - return _buffer[_position++]==0 ? false : true; + return getBoolean(_position++); + } + + bool ByteBuffer::getBoolean(int index) { + if(index>=0&&index<_limit) + return _buffer[index]==0 ? false : true; else - throw EpicsException("buffer underflow"); + throw EpicsException("index out of bounds"); } int8 ByteBuffer::getByte() { - if(_position<_limit) - return (int8)_buffer[_position++]; + return getByte(_position++); + } + + int8 ByteBuffer::getByte(int index) { + if(index>=0&&index<_limit) + return (int8)_buffer[index]; else - throw EpicsException("buffer underflow"); + throw EpicsException("index out of bounds"); } int16 ByteBuffer::getShort() { @@ -74,6 +81,15 @@ namespace epics { return val; } + int16 ByteBuffer::getShort(int index) { + if(index<0||_limit-index<(int)sizeof(int16)) + throw EpicsException("index out of bounds"); + int16 val; + getWithEndianness(index, (char*)&val, sizeof(int16)); // store short into val + return val; + + } + int32 ByteBuffer::getInt() { if(_limit-_position<(int)sizeof(int32)) throw EpicsException("buffer underflow"); @@ -82,6 +98,14 @@ namespace epics { return val; } + int32 ByteBuffer::getInt(int index) { + if(index<0||_limit-index<(int)sizeof(int32)) + throw EpicsException("index out of bounds"); + int32 val; + getWithEndianness(index, (char*)&val, sizeof(int32)); // store int into val + return val; + } + int64 ByteBuffer::getLong() { if(_limit-_position<(int)sizeof(int64)) throw EpicsException("buffer underflow"); @@ -90,6 +114,14 @@ namespace epics { return val; } + int64 ByteBuffer::getLong(int index) { + if(index<0||_limit-index<(int)sizeof(int64)) + throw EpicsException("index out of bounds"); + int64 val; + getWithEndianness(index, (char*)&val, sizeof(int64)); // store long into val + return val; + } + float ByteBuffer::getFloat() { if(_limit-_position<(int)sizeof(float)) throw EpicsException("buffer underflow"); @@ -98,6 +130,14 @@ namespace epics { return val; } + float ByteBuffer::getFloat(int index) { + if(index<0||_limit-index<(int)sizeof(float)) + throw EpicsException("index out of bounds"); + float val; + getWithEndianness(index, (char*)&val, sizeof(float)); // store float into val + return val; + } + double ByteBuffer::getDouble() { if(_limit-_position<(int)sizeof(double)) throw EpicsException("buffer underflow"); @@ -106,6 +146,14 @@ namespace epics { return val; } + double ByteBuffer::getDouble(int index) { + if(index>=0&&_limit-index<(int)sizeof(double)) throw EpicsException( + "index out of bounds"); + double val; + getWithEndianness(index, (char*)&val, sizeof(double)); // store double into val + return val; + } + void ByteBuffer::get(char* dst, int offset, int count) { if(count>getRemaining()) throw EpicsException("buffer underflow"); for(int i = 0; i=0&&index<_limit) + _buffer[index] = (char)value; else - throw EpicsException("buffer overflow"); + throw EpicsException("index out of bounds"); return this; } @@ -142,6 +194,13 @@ namespace epics { return this; } + ByteBuffer* ByteBuffer::putShort(int index, int16 value) { + if(index<0||_limit-index<(int)sizeof(int16)) + throw EpicsException("index out of bounds"); + putWithEndianness(index, (char*)&value, sizeof(int16)); // store short into buffer + return this; + } + ByteBuffer* ByteBuffer::putInt(int32 value) { if(_limit-_position<(int)sizeof(int32)) throw EpicsException("buffer overflow"); @@ -149,6 +208,13 @@ namespace epics { return this; } + ByteBuffer* ByteBuffer::putInt(int index, int32 value) { + if(index<0||_limit-index<(int)sizeof(int32)) + throw EpicsException("index out of bounds"); + putWithEndianness(index, (char*)&value, sizeof(int32)); // store int into buffer + return this; + } + ByteBuffer* ByteBuffer::putLong(int64 value) { if(_limit-_position<(int)sizeof(int64)) throw EpicsException("buffer overflow"); @@ -156,6 +222,13 @@ namespace epics { return this; } + ByteBuffer* ByteBuffer::putLong(int index, int64 value) { + if(index<0||_limit-index<(int)sizeof(int64)) + throw EpicsException("index out of bounds"); + putWithEndianness(index, (char*)&value, sizeof(int64)); // store long into buffer + return this; + } + ByteBuffer* ByteBuffer::putFloat(float value) { if(_limit-_position<(int)sizeof(float)) throw EpicsException("buffer overflow"); @@ -163,6 +236,13 @@ namespace epics { return this; } + ByteBuffer* ByteBuffer::putFloat(int index, float value) { + if(index<0||_limit-index<(int)sizeof(float)) + throw EpicsException("index out of bounds"); + putWithEndianness(index, (char*)&value, sizeof(float)); // store float into buffer + return this; + } + ByteBuffer* ByteBuffer::putDouble(double value) { if(_limit-_position<(int)sizeof(double)) throw EpicsException("buffer overflow"); @@ -170,6 +250,13 @@ namespace epics { return this; } + ByteBuffer* ByteBuffer::putDouble(int index, double value) { + if(index<0||_limit-index<(int)sizeof(double)) + throw EpicsException("index out of bounds"); + putWithEndianness(index, (char*)&value, sizeof(double)); // store double into buffer + return this; + } + /** * Buffer underflow or overflow checks are performed in the caller. */ @@ -194,5 +281,29 @@ namespace epics { _buffer[_position++] = src[i]; } + /** + * Buffer underflow or overflow checks are performed in the caller. + */ + void ByteBuffer::putWithEndianness(int index, char* src, size_t size) { + if(_bufferByteOrder==EPICS_BYTE_ORDER) + for(size_t i = 0; i=0; i--) + _buffer[index++] = src[i]; + } + + /** + * Buffer underflow or overflow checks are performed in the caller. + */ + void ByteBuffer::getWithEndianness(int index, char* dest, size_t size) { + if(_bufferByteOrder==EPICS_BYTE_ORDER) + for(size_t i = 0; i=0; i--) + dest[i] = _buffer[index++]; + } + } } diff --git a/pvDataApp/misc/byteBuffer.h b/pvDataApp/misc/byteBuffer.h index 8e48e5d..75ea78f 100644 --- a/pvDataApp/misc/byteBuffer.h +++ b/pvDataApp/misc/byteBuffer.h @@ -16,21 +16,20 @@ namespace epics { namespace pvData { - /** @brief A buffer of bytes. - * - * A buffer of bytes, which has - * - capacity (size) - * - limit - * - position - * The capacity is the maximum capacity of the buffer, the buffer's - * limit is the index of the first element that should not be read or - * written, and its position is the index of the next element to be - * written. - * - * The buffer also ha a byte order specified which can be little or - * big endian. - */ + * + * A buffer of bytes, which has + * - capacity (size) + * - limit + * - position + * The capacity is the maximum capacity of the buffer, the buffer's + * limit is the index of the first element that should not be read or + * written, and its position is the index of the next element to be + * written. + * + * The buffer also ha a byte order specified which can be little or + * big endian. + */ class ByteBuffer { public: /** @brief ByteBuffer constructor. @@ -78,6 +77,16 @@ namespace epics { */ bool getBoolean(); + /** + * Absolute get method. Reads the bool at the given {@code index}. + * + * @param[in] index The index from which the bool will be read + * @returns The bool at the given index + * @throws EpicsException - If index is negative or not smaller + * than the buffer's limit + */ + bool getBoolean(int index); + /** * Relative Int8 read, {@code position} is incremented by * {@code 1}. @@ -88,6 +97,16 @@ namespace epics { */ int8 getByte(); + /** + * Absolute get method. Reads the byte at the given {@code index}. + * + * @param[in] index The index from which the byte will be read + * @returns The byte at the given index + * @throws EpicsException - If index is negative or not smaller + * than the buffer's limit + */ + int8 getByte(int index); + /** * Relative Int16 read, {@code position} is incremented by * {@code 2}. @@ -98,6 +117,16 @@ namespace epics { */ int16 getShort(); + /** + * Absolute get method. Reads the int16 at the given {@code index}. + * + * @param[in] index The index from which the int16 will be read + * @returns The int16 at the given index + * @throws EpicsException - If index is negative or not within + * the buffer's limit + */ + int16 getShort(int index); + /** * Relative Int32 read, {@code position} is incremented by * {@code 4}. @@ -108,6 +137,16 @@ namespace epics { */ int32 getInt(); + /** + * Absolute get method. Reads the int32 at the given {@code index}. + * + * @param[in] index The index from which the int32 will be read + * @returns The int32 at the given index + * @throws EpicsException - If index is negative or not within + * the buffer's limit + */ + int32 getInt(int index); + /** * Relative Int64 read, {@code position} is incremented by * {@code 8}. @@ -118,6 +157,16 @@ namespace epics { */ int64 getLong(); + /** + * Absolute get method. Reads the int64 at the given {@code index}. + * + * @param[in] index The index from which the int64 will be read + * @returns The int64 at the given index + * @throws EpicsException - If index is negative or not within + * the buffer's limit + */ + int64 getLong(int index); + /** * Relative float read, {@code position} is incremented by * {@code 4}. @@ -128,6 +177,16 @@ namespace epics { */ float getFloat(); + /** + * Absolute get method. Reads the float at the given {@code index}. + * + * @param[in] index The index from which the float will be read + * @returns The float at the given index + * @throws EpicsException - If index is negative or not within + * the buffer's limit + */ + float getFloat(int index); + /** * Relative double read, {@code position} is incremented by * {@code 8}. @@ -138,6 +197,16 @@ namespace epics { */ double getDouble(); + /** + * Absolute get method. Reads the double at the given {@code index}. + * + * @param[in] index The index from which the double will be read + * @returns The double at the given index + * @throws EpicsException - If index is negative or not within + * the buffer's limit + */ + double getDouble(int index); + /** * Relative bulk @em get method. It transfers {@code count} bytes * from the buffer into the {@code dst}. @@ -176,6 +245,15 @@ namespace epics { */ ByteBuffer* putBoolean(bool value); + /** + * Absolute bool write. + * + * @param[in] index The index at which the bool will be written. + * @param[in] value The bool value to write. + * @throws EpicsException - Buffer overflow if there are no + * bytes remaining in the buffer. + */ + ByteBuffer* putBoolean(int index, bool value); /** * Relative Int8 write, {@code position} is incremented by @@ -187,6 +265,16 @@ namespace epics { */ ByteBuffer* putByte(int8 value); + /** + * Absolute Int8 write. + * + * @param[in] index The index at which the byte will be written. + * @param[in] value The Int8 value to write. + * @throws EpicsException - Buffer overflow if there are no + * bytes remaining in the buffer. + */ + ByteBuffer* putByte(int index, int8 value); + /** * Relative Int16 write, {@code position} is incremented by * {@code 2}. @@ -197,6 +285,16 @@ namespace epics { */ ByteBuffer* putShort(int16 value); + /** + * Absolute Int16 write. + * + * @param[in] index The index at which the Int16 will be written. + * @param[in] value The Int16 value to write. + * @throws EpicsException - Buffer overflow if there are less than + * 2 bytes remaining in the buffer. + */ + ByteBuffer* putShort(int index, int16 value); + /** * Relative Int32 write, {@code position} is incremented by * {@code 4}. @@ -207,6 +305,16 @@ namespace epics { */ ByteBuffer* putInt(int32 value); + /** + * Absolute Int32 write. + * + * @param[in] index The index at which the Int32 will be written. + * @param[in] value The Int32 value to write. + * @throws EpicsException - Buffer overflow if there are less than + * 4 bytes remaining in the buffer. + */ + ByteBuffer* putInt(int index, int32 value); + /** * Relative Int64 write, {@code position} is incremented by * {@code 8}. @@ -217,6 +325,16 @@ namespace epics { */ ByteBuffer* putLong(int64 value); + /** + * Absolute Int64 write. + * + * @param[in] index The index at which the Int64 will be written. + * @param[in] value The Int64 value to write. + * @throws EpicsException - Buffer overflow if there are less than + * 8 bytes remaining in the buffer. + */ + ByteBuffer* putLong(int index, int64 value); + /** * Relative float write, {@code position} is incremented by * {@code 4}. @@ -227,6 +345,16 @@ namespace epics { */ ByteBuffer* putFloat(float value); + /** + * Absolute float write. + * + * @param[in] index The index at which the float will be written. + * @param[in] value The float value to write. + * @throws EpicsException - Buffer overflow if there are less than + * 4 bytes remaining in the buffer. + */ + ByteBuffer* putFloat(int index, float value); + /** * Relative float write, {@code position} is incremented by * {@code 8}. @@ -237,6 +365,16 @@ namespace epics { */ ByteBuffer* putDouble(double value); + /** + * Absolute double write. + * + * @param[in] index The index at which the double will be written. + * @param[in] value The double value to write. + * @throws EpicsException - Buffer overflow if there are less than + * 8 bytes remaining in the buffer. + */ + ByteBuffer* putDouble(int index, double value); + //virtual ByteBuffer *putString(String value) = 0; // TODO /** @@ -321,7 +459,13 @@ namespace epics { "invalid limit"); _position = newPosition; } - + + inline void setLimit(int newLimit) { + if(newLimit<0||_position>newLimit) throw EpicsException( + "invalid limit"); + _limit = newLimit; + } + // TODO must define arrays private: @@ -334,12 +478,28 @@ namespace epics { * and the current hardware. */ void getWithEndianness(char* dest, size_t size); + /** * Puts the next
size
bytes into the buffer reading them * from source taking into account endianness of the buffer * and the current hardware. */ void putWithEndianness(char* src, size_t size); + + /** + * Puts the
size
bytes into the buffer reading them + * from source taking into account endianness of the buffer + * and the current hardware. + */ + void putWithEndianness(int index, char* src, size_t size); + + /** + * Reads the next
size
bytes from the buffer and stores them + * into the destination taking into account endianness of the buffer + * and the current hardware. + */ + void getWithEndianness(int index, char* dest, size_t size); + }; } diff --git a/testApp/misc/testByteBuffer.cpp b/testApp/misc/testByteBuffer.cpp index 40c68b0..551eab9 100644 --- a/testApp/misc/testByteBuffer.cpp +++ b/testApp/misc/testByteBuffer.cpp @@ -62,6 +62,15 @@ void testBasicOperations() { assert(buff->getPosition()==28); assert(buff->getRemaining()==4); + // testing direct reads + assert(buff->getBoolean(0)==true); + assert(buff->getByte(1)==-12); + assert(buff->getShort(2)==10516); + assert(buff->getInt(4)==0x1937628B); + assert(buff->getLong(8)==2345678123LL); + assert(buff->getFloat(16)==testFloat); + assert(buff->getDouble(20)==testDouble); + buff->flip(); assert(buff->getLimit()==28); assert(buff->getPosition()==0); @@ -103,6 +112,43 @@ void testBasicOperations() { assert(buff->getLimit()==32); assert(buff->getRemaining()==(32-13)); + // testing absolute puts + buff->clear(); + buff->setPosition(28); + buff->putBoolean(0, true); + buff->putByte(1, -12); + buff->putShort(2, 10516); + buff->putInt(4, 0x1937628B); + buff->putLong(8, 2345678123LL); + buff->putFloat(16, testFloat); + buff->putDouble(20, testDouble); + + buff->flip(); + assert(buff->getLimit()==28); + assert(buff->getPosition()==0); + assert(buff->getRemaining()==28); + + assert(buff->getBoolean()==true); + assert(buff->getPosition()==1); + + assert(buff->getByte()==-12); + assert(buff->getPosition()==2); + + assert(buff->getShort()==10516); + assert(buff->getPosition()==4); + + assert(buff->getInt()==0x1937628B); + assert(buff->getPosition()==8); + + assert(buff->getLong()==2345678123LL); + assert(buff->getPosition()==16); + + assert(buff->getFloat()==testFloat); + assert(buff->getPosition()==20); + + assert(buff->getDouble()==testDouble); + assert(buff->getPosition()==28); + buff->clear(); assert(buff->getPosition()==0); assert(buff->getLimit()==32);