byteBuffer added

This commit is contained in:
Matej Sekoranja
2010-10-21 14:28:34 +02:00
parent f7c89f2ed9
commit 7cf33be144
9 changed files with 650 additions and 31 deletions

View File

@@ -73,4 +73,9 @@ pvDataApp/test/testIntrospect.cpp
pvDataApp/test/testPVAuxInfo.cpp
pvDataApp/test/testPVScalar.cpp
pvDataApp/test/testPVScalarArray.cpp
pvDataApp/test/testSimpleStructure.cpp
pvDataApp/test/testSimpleStructure.cpp
pvDataApp/misc/epicsException.h
pvDataApp/misc/byteBuffer.cpp
pvDataApp/misc/bitSet.cpp
pvDataApp/test/testByteBuffer.cpp
pvDataApp/test/testBitSet.cpp

View File

@@ -8,7 +8,9 @@ INC += requester.h
INC += serialize.h
INC += bitSet.h
INC += byteBuffer.h
INC += epicsException.h
LIBSRCS += byteBuffer.cpp
LIBSRCS += bitSet.cpp
LIBRARY=pvMisc

View File

@@ -1,3 +1,5 @@
#include "string.h"
#include "stdio.h"
#include "bitSet.h"
namespace epics { namespace pvData {
@@ -302,6 +304,11 @@ namespace epics { namespace pvData {
return true;
}
bool BitSet::operator!=(const BitSet &set) const
{
return !(*this == set);
}
void BitSet::toString(StringBuilder buffer) { toString(buffer, 0); }
void BitSet::toString(StringBuilder buffer, int indentLevel) const

View File

@@ -210,6 +210,8 @@ namespace epics { namespace pvData {
*/
bool operator==(const BitSet &set) const;
bool operator!=(const BitSet &set) const;
void toString(StringBuilder buffer);
void toString(StringBuilder buffer, int indentLevel) const;

View File

@@ -0,0 +1,180 @@
/*
* byteBuffer.cpp
*
* Created on: Oct 18, 2010
* Author: Miha Vitorovic
*/
#include "byteBuffer.h"
#include "epicsException.h"
namespace epics {
namespace pvData {
using std::stringstream;
ByteBuffer::ByteBuffer(int size, int byteOrder) :
_bufferByteOrder(byteOrder), _size(size), _position(0),
_limit(size), _buffer(0) {
if (size < 0)
throw EpicsException("negative size");
if (byteOrder!=EPICS_ENDIAN_BIG && byteOrder!=EPICS_ENDIAN_LITTLE)
throw EpicsException("invalid endian");
_buffer = new char[_size];
}
ByteBuffer::~ByteBuffer() {
if (_buffer) delete _buffer;
}
ByteBuffer* ByteBuffer::clear() {
_position = 0;
_limit = _size;
return this;
}
ByteBuffer* ByteBuffer::flip() {
_limit = _position;
_position = 0;
return this;
}
ByteBuffer* ByteBuffer::rewind() {
_position = 0;
return this;
}
bool ByteBuffer::getBoolean() {
if(_position<_limit)
return _buffer[_position++]==0 ? false : true;
else
throw EpicsException("buffer underflow");
}
epicsInt8 ByteBuffer::getByte() {
if(_position<_limit)
return (epicsInt8)_buffer[_position++];
else
throw EpicsException("buffer underflow");
}
epicsInt16 ByteBuffer::getShort() {
if(_limit-_position<(int)sizeof(epicsInt16))
throw EpicsException("buffer underflow");
epicsInt16 val;
getWithEndianness((char*)&val, sizeof(epicsInt16)); // store short into val
return val;
}
epicsInt32 ByteBuffer::getInt() {
if(_limit-_position<(int)sizeof(epicsInt32))
throw EpicsException("buffer underflow");
epicsInt32 val;
getWithEndianness((char*)&val, sizeof(epicsInt32)); // store int into val
return val;
}
epicsInt64 ByteBuffer::getLong() {
if(_limit-_position<(int)sizeof(epicsInt64))
throw EpicsException("buffer underflow");
epicsInt64 val;
getWithEndianness((char*)&val, sizeof(epicsInt64)); // store long into val
return val;
}
float ByteBuffer::getFloat() {
if(_limit-_position<(int)sizeof(float))
throw EpicsException("buffer underflow");
float val;
getWithEndianness((char*)&val, sizeof(float)); // store float into val
return val;
}
double ByteBuffer::getDouble() {
if(_limit-_position<(int)sizeof(double))
throw EpicsException("buffer underflow");
double val;
getWithEndianness((char*)&val, sizeof(double)); // store double into val
return val;
}
ByteBuffer* ByteBuffer::putBoolean(bool value) {
if(_position<_limit)
_buffer[_position++] = value ? 1 : 0;
else
throw EpicsException("buffer overflow");
return this;
}
ByteBuffer* ByteBuffer::putByte(epicsInt8 value) {
if(_position<_limit)
_buffer[_position++] = (char)value;
else
throw EpicsException("buffer overflow");
return this;
}
ByteBuffer* ByteBuffer::putShort(epicsInt16 value) {
if(_limit-_position<(int)sizeof(epicsInt16))
throw EpicsException("buffer overflow");
putWithEndianness((char*)&value, sizeof(epicsInt16)); // store short into buffer
return this;
}
ByteBuffer* ByteBuffer::putInt(epicsInt32 value) {
if(_limit-_position<(int)sizeof(epicsInt32))
throw EpicsException("buffer overflow");
putWithEndianness((char*)&value, sizeof(epicsInt32)); // store int into buffer
return this;
}
ByteBuffer* ByteBuffer::putLong(epicsInt64 value) {
if(_limit-_position<(int)sizeof(epicsInt64))
throw EpicsException("buffer overflow");
putWithEndianness((char*)&value, sizeof(epicsInt64)); // store long into buffer
return this;
}
ByteBuffer* ByteBuffer::putFloat(float value) {
if(_limit-_position<(int)sizeof(float))
throw EpicsException("buffer overflow");
putWithEndianness((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");
putWithEndianness((char*)&value, sizeof(double)); // store double into buffer
return this;
}
/**
* Buffer underflow or overflow checks are performed in the caller.
*/
void ByteBuffer::getWithEndianness(char* dest, size_t size) {
if(_bufferByteOrder==EPICS_BYTE_ORDER)
for(size_t i = 0; i<size; i++)
dest[i] = _buffer[_position++];
else
for(int i = (int)size-1; i>=0; i--)
dest[i] = _buffer[_position++];
}
/**
* Buffer underflow or overflow checks are performed in the caller.
*/
void ByteBuffer::putWithEndianness(char* src, size_t size) {
if(_bufferByteOrder==EPICS_BYTE_ORDER)
for(size_t i = 0; i<size; i++)
_buffer[_position++] = src[i];
else
for(int i = (int)size-1; i>=0; i--)
_buffer[_position++] = src[i];
}
}
}

View File

@@ -1,38 +1,302 @@
/* byteBuffer.h */
#include <string>
#ifndef BYTEBUFFER_H
#define BYTEBUFFER_H
#include "epicsTypes.h"
namespace epics { namespace pvData {
// not sure why I have to define epicsInt64
typedef long long epicsInt64;
#include <string>
#include <epicsTypes.h>
#include <epicsEndian.h>
class ByteBuffer;
namespace epics {
namespace pvData {
class ByteBuffer {
public:
virtual ~ByteBuffer();
virtual int getSize() = 0;
virtual int getArrayOffset() = 0;
virtual bool getBoolean() = 0;
virtual epicsInt8 getByte() = 0;
virtual epicsInt16 geShort() = 0;
virtual epicsInt32 getInt() = 0;
virtual epicsInt64 getLong() = 0;
virtual float getFloat() = 0;
virtual double getDouble() = 0;
virtual String getString() = 0;
virtual ByteBuffer *putBoolean(bool value) = 0;
virtual ByteBuffer *putByte(epicsInt8 value) = 0;
virtual ByteBuffer *geShort(epicsInt16 value) = 0;
virtual ByteBuffer *putInt(epicsInt32 value) = 0;
virtual ByteBuffer *putLong(epicsInt64 value) = 0;
virtual ByteBuffer *putFloat(float value) = 0;
virtual ByteBuffer *putDouble(double value) = 0;
virtual ByteBuffer *putString(String value) = 0;
// Must define arrays
};
// not sure why I have to define epicsInt64
typedef long long epicsInt64;
}}
/** @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.
*/
class ByteBuffer {
public:
/** @brief ByteBuffer constructor.
*
* Creates a buffer of a given size, and with a specified byteOrder.
*
* @param size Specify the capacity of the buffer. Default is 32.
* @param byteOrder the byte order of the buffer. Can be either
* EPICS_ENDIAN_LITTLE or EPICS_ENDIAN_BIG.
*/
ByteBuffer(int size = 32, int byteOrder = EPICS_BYTE_ORDER);
/**
* @brief ByteBuffer destructor.
*/
~ByteBuffer();
/**
* Clears the buffer. Sets the {@code position} to 0 and {@code limit}
* to {@code capacity}.
*/
ByteBuffer* clear();
/**
* Flips the buffer. The {@code limit} is set to the current {@code position}
* and the {@code position} is set to {@code 0}. This prepares the
* buffer for a series of relative @em get operations after a series
* of relative @em put operations.
*/
ByteBuffer* flip();
/**
* Rewinds the buffer. This sets {@code position} to {@code 0}
* without affecting the {@code limit}.
*/
ByteBuffer* rewind();
/**
* Relative boolean read, {@code position} is incremented by
* {@code 1}.
*
* @returns The next byte in the buffer as a boolean.
* @throws EpicsException - Buffer underflow if there are no bytes
* remaining in the buffer.
*/
bool getBoolean();
/**
* Relative Int8 read, {@code position} is incremented by
* {@code 1}.
*
* @returns The next byte in the buffer as a signed Int8.
* @throws EpicsException - Buffer underflow if there are no bytes
* remaining in the buffer.
*/
epicsInt8 getByte();
/**
* Relative Int16 read, {@code position} is incremented by
* {@code 2}.
*
* @returns The next Int16 value in the buffer.
* @throws EpicsException - Buffer underflow if there are less than
* 2 bytes remaining in the buffer.
*/
epicsInt16 getShort();
/**
* Relative Int32 read, {@code position} is incremented by
* {@code 4}.
*
* @returns The next Int32 value in the buffer.
* @throws EpicsException - Buffer underflow if there are less than
* 4 bytes remaining in the buffer.
*/
epicsInt32 getInt();
/**
* Relative Int64 read, {@code position} is incremented by
* {@code 8}.
*
* @returns The next Int64 value in the buffer.
* @throws EpicsException - Buffer underflow if there are less than
* 8 bytes remaining in the buffer.
*/
epicsInt64 getLong();
/**
* Relative float read, {@code position} is incremented by
* {@code 4}.
*
* @returns The next float value in the buffer.
* @throws EpicsException - Buffer underflow if there are less than
* 4 bytes remaining in the buffer.
*/
float getFloat();
/**
* Relative double read, {@code position} is incremented by
* {@code 8}.
*
* @returns The next double value in the buffer.
* @throws EpicsException - Buffer underflow if there are less than
* 8 bytes remaining in the buffer.
*/
double getDouble();
//virtual String getString() = 0; // TODO
/**
* Relative boolean write, {@code position} is incremented by
* {@code 1}.
*
* @param[in] value The boolean value to write.
* @throws EpicsException - Buffer overflow if there are no
* bytes remaining in the buffer.
*/
ByteBuffer* putBoolean(bool value);
/**
* Relative Int8 write, {@code position} is incremented by
* {@code 1}.
*
* @param[in] value The Int8 value to write.
* @throws EpicsException - Buffer overflow if there are no
* bytes remaining in the buffer.
*/
ByteBuffer* putByte(epicsInt8 value);
/**
* Relative Int16 write, {@code position} is incremented by
* {@code 2}.
*
* @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(epicsInt16 value);
/**
* Relative Int32 write, {@code position} is incremented by
* {@code 4}.
*
* @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(epicsInt32 value);
/**
* Relative Int64 write, {@code position} is incremented by
* {@code 8}.
*
* @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(epicsInt64 value);
/**
* Relative float write, {@code position} is incremented by
* {@code 4}.
*
* @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(float value);
/**
* Relative float write, {@code position} is incremented by
* {@code 8}.
*
* @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(double value);
//virtual ByteBuffer *putString(String value) = 0; // TODO
/**
* The capacity (size) of the buffer in bytes.
*
* @returns The capacity of the buffer in bytes.
*/
inline int getSize() const {
return _size;
}
/**
* The offset from the start of the buffer in bytes. Currently this
* method always returns {@code 0}.
*
* @returns The offset from the start of the buffer in bytes
*/
inline int getArrayOffset() const {
return 0;
}
/**
* The byte index of the next element to @em get or @em put.
*
* @returns The byte index of the next element.
*/
inline int getPosition() const {
return _position;
}
/**
* The byte index of the {@code limit}. {@code limit} is always less
* or equal to the buffer capacity. No @em put or @em get operation
* can be performed pass the {@code limit}.
*
* @returns The byte index of the {@code limit}.
*/
inline int getLimit() const {
return _limit;
}
/**
* The number of the bytes that can be successfully read or written.
*
* @returns The number of the bytes that can be successfully read or
* written.
*/
inline int getRemaining() const {
return _limit-_position;
}
/**
* The byte order of the buffer.
*
* @returns Either {@code EPICS_ENDIAN_LITTLE} or
* {@code EPICS_ENDIAN_BIG}.
*/
inline int getByteOrder() const {
return _bufferByteOrder;
}
/**
* Gives a read-only access to the buffer.
*
* @returns A const (read-only) pointer to the actual buffer.
*/
inline const char* getArray() const {
return _buffer;
}
// TODO must define arrays
private:
int _bufferByteOrder, _size, _position, _limit;
char* _buffer;
/**
* Reads the next <pre>size</pre> bytes from the buffer and stores them
* into the destination taking into account endianness of the buffer
* and the current hardware.
*/
void getWithEndianness(char* dest, size_t size);
/**
* Puts the next <pre>size</pre> 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);
};
}
}
#endif /* BYTEBUFFER_H */

View File

@@ -0,0 +1,29 @@
/*
* epicsException.hpp
*
* Created on: Oct 18, 2010
* Author: miha_vitorovic
*/
#ifndef EPICSEXCEPTION_H_
#define EPICSEXCEPTION_H_
// TODO to be redefined!!!!!!
#include <stdexcept>
#include <string>
namespace epics { namespace pvData {
/** Base Epics Exception */
class EpicsException : public std::logic_error {
public:
explicit EpicsException(const std::string& arg) :
std::logic_error(arg) {
}
};
}
}
#endif /* EPICSEXCEPTION_H_ */

View File

@@ -26,6 +26,10 @@ PROD_HOST += testBitSet
testBitSet_SRCS += testBitSet.cpp
testBitSet_LIBS += pvMisc Com
PROD_HOST += testByteBuffer
testByteBuffer_SRCS += testByteBuffer.cpp
testByteBuffer_LIBS += pvMisc Com
include $(TOP)/configure/RULES
#----------------------------------------
# ADD RULES AFTER THIS LINE

View File

@@ -0,0 +1,126 @@
/*
* testByteBuffer.cpp
*
* Created on: Oct 20, 2010
* Author: Miha Vitorovic
*/
#include <iostream>
#include <cstring>
#include <epicsAssert.h>
#include <epicsEndian.h>
#include "byteBuffer.h"
using namespace epics::pvData;
using std::cout;
void testBasicOperations() {
cout<<"Basic operation tests...\n";
ByteBuffer* buff = new ByteBuffer();
assert(buff->getSize()==32);
assert(buff->getByteOrder()==EPICS_BYTE_ORDER);
assert(buff->getPosition()==0);
assert(buff->getLimit()==32);
assert(buff->getRemaining()==32);
buff->putBoolean(true);
assert(buff->getPosition()==1);
assert(buff->getRemaining()==31);
buff->putByte(-12);
assert(buff->getPosition()==2);
assert(buff->getRemaining()==30);
buff->putShort(10516);
assert(buff->getPosition()==4);
assert(buff->getRemaining()==28);
buff->putInt(0x1937628B);
assert(buff->getPosition()==8);
assert(buff->getRemaining()==24);
buff->putLong(2345678123LL);
assert(buff->getPosition()==16);
assert(buff->getRemaining()==16);
float testFloat = 34.67;
buff->putFloat(testFloat);
assert(buff->getPosition()==20);
assert(buff->getRemaining()==12);
double testDouble = -512.23974;
buff->putDouble(testDouble);
assert(buff->getPosition()==28);
assert(buff->getRemaining()==4);
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);
assert(buff->getRemaining()==32);
delete buff;
cout<<" PASSED\n";
}
void testInverseEndianness() {
cout<<"Testing inverse endianness...\n";
#if EPICS_BYTE_ORDER==EPICS_ENDIAN_BIG
ByteBuffer* buff = new ByteBuffer(32,EPICS_ENDIAN_LITTLE);
char refBuffer[] =
{ (char)0x02, (char)0x01, (char)0x0D, (char)0x0C, (char)0x0B, (char)0x0A};
#else
ByteBuffer* buff = new ByteBuffer(32, EPICS_ENDIAN_BIG);
char refBuffer[] = { (char)0x01, (char)0x02, (char)0x0A, (char)0x0B,
(char)0x0C, (char)0x0D };
#endif
buff->putShort(0x0102);
buff->putInt(0x0A0B0C0D);
assert(strncmp(buff->getArray(),refBuffer,6)==0);
buff->flip();
assert(buff->getShort()==0x0102);
assert(buff->getInt()==0x0A0B0C0D);
delete buff;
cout<<" PASSED\n";
}
int main(int argc, char *argv[]) {
testBasicOperations();
testInverseEndianness();
return (0);
}