diff --git a/pvDataCPP.files b/pvDataCPP.files index a724cc8..10cd1dc 100644 --- a/pvDataCPP.files +++ b/pvDataCPP.files @@ -233,3 +233,4 @@ testApp/pv/testPVStructureArray.cpp testApp/pv/testPVType.cpp testApp/pv/testStandardField.cpp testApp/pv/testStandardPVField.cpp +src/factory/printer.cpp diff --git a/src/factory/PVDataCreateFactory.cpp b/src/factory/PVDataCreateFactory.cpp index bcd1bad..aa0262f 100644 --- a/src/factory/PVDataCreateFactory.cpp +++ b/src/factory/PVDataCreateFactory.cpp @@ -190,6 +190,19 @@ void BasePVString::serialize(ByteBuffer *pbuffer, SerializeHelper::serializeSubstring(value, offset, count, pbuffer, pflusher); } +void PVArray::checkLength(size_t len) +{ + Array::ArraySizeType type = getArray()->getArraySizeType(); + if (type != Array::variable) + { + size_t size = getArray()->getMaximumCapacity(); + if (type == Array::fixed && len != size) + throw std::invalid_argument("invalid length for a fixed size array"); + else if (type == Array::bounded && len > size) + throw std::invalid_argument("new array capacity too large for a bounded size array"); + } +} + /** Default storage for arrays */ template @@ -231,7 +244,14 @@ DefaultPVArray::DefaultPVArray(ScalarArrayConstPtr const & scalarArray) : PVValueArray(scalarArray), value() -{ } +{ + ArrayConstPtr array = this->getArray(); + if (array->getArraySizeType() == Array::fixed) + { + // this->setLength(array->getMaximumCapacity()); + this->setCapacityMutable(false); + } +} template DefaultPVArray::~DefaultPVArray() @@ -240,18 +260,25 @@ template void DefaultPVArray::setCapacity(size_t capacity) { if(this->isCapacityMutable()) { + this->checkLength(capacity); value.reserve(capacity); } + else + THROW_EXCEPTION2(std::logic_error, "capacity immutable"); } template void DefaultPVArray::setLength(size_t length) { if(this->isImmutable()) - THROW_EXCEPTION2(std::logic_error,"Immutable"); - if(length == value.size()) + THROW_EXCEPTION2(std::logic_error, "immutable"); + + if (length == value.size()) return; - else if(length < value.size()) + + this->checkLength(length); + + if (length < value.size()) value.slice(0, length); else value.resize(length); @@ -260,6 +287,8 @@ void DefaultPVArray::setLength(size_t length) template void DefaultPVArray::replace(const const_svector& next) { + this->checkLength(next.size()); + value = next; this->postPut(); } @@ -267,8 +296,10 @@ void DefaultPVArray::replace(const const_svector& next) template void DefaultPVArray::swap(const_svector &other) { - if(this->isImmutable()) - THROW_EXCEPTION2(std::logic_error,"Immutable"); + if (this->isImmutable()) + THROW_EXCEPTION2(std::logic_error, "immutable"); + + // no checkLength call here value.swap(other); } @@ -283,7 +314,10 @@ void DefaultPVArray::serialize(ByteBuffer *pbuffer, template void DefaultPVArray::deserialize(ByteBuffer *pbuffer, DeserializableControl *pcontrol) { - size_t size = SerializeHelper::readSize(pbuffer, pcontrol); + + size_t size = this->getArray()->getArraySizeType() == Array::fixed ? + this->getArray()->getMaximumCapacity() : + SerializeHelper::readSize(pbuffer, pcontrol); svector nextvalue(thaw(value)); nextvalue.resize(size); // TODO: avoid copy of stuff we will then overwrite @@ -321,6 +355,7 @@ void DefaultPVArray::deserialize(ByteBuffer *pbuffer, remaining -= n2read; } value = freeze(nextvalue); + // TODO !!! // inform about the change? PVField::postPut(); } @@ -334,7 +369,11 @@ void DefaultPVArray::serialize(ByteBuffer *pbuffer, temp.slice(offset, count); count = temp.size(); - SerializeHelper::writeSize(temp.size(), pbuffer, pflusher); + ArrayConstPtr array = this->getArray(); + if (array->getArraySizeType() != Array::fixed) + SerializeHelper::writeSize(count, pbuffer, pflusher); + else if (count != array->getMaximumCapacity()) + throw std::length_error("fixed array cannot be partially serialized"); const T* cur = temp.data(); @@ -368,7 +407,10 @@ void DefaultPVArray::serialize(ByteBuffer *pbuffer, template<> void DefaultPVArray::deserialize(ByteBuffer *pbuffer, DeserializableControl *pcontrol) { - size_t size = SerializeHelper::readSize(pbuffer, pcontrol); + + size_t size = this->getArray()->getArraySizeType() == Array::fixed ? + this->getArray()->getMaximumCapacity() : + SerializeHelper::readSize(pbuffer, pcontrol); svector nextvalue(thaw(value)); @@ -396,7 +438,9 @@ void DefaultPVArray::serialize(ByteBuffer *pbuffer, const_svector temp(value); temp.slice(offset, count); - SerializeHelper::writeSize(temp.size(), pbuffer, pflusher); + // TODO if fixed count == getArray()->getMaximumCapacity() + if (this->getArray()->getArraySizeType() != Array::fixed) + SerializeHelper::writeSize(temp.size(), pbuffer, pflusher); const string * pvalue = temp.data(); for(size_t i = 0; igetLength()) + else if (offset+number>getLength()) + return false; + else if (getArray()->getArraySizeType() == Array::fixed) return false; svector vec(reuse()); @@ -65,6 +69,9 @@ bool PVStructureArray::remove(size_t offset,size_t number) } void PVStructureArray::compress() { + if (getArray()->getArraySizeType() == Array::fixed) + return; + svector vec(reuse()); // TODO: check for first NULL before realloc size_t length = vec.size(); @@ -99,7 +106,8 @@ void PVStructureArray::compress() { void PVStructureArray::setCapacity(size_t capacity) { - if(this->isCapacityMutable()) { + if (this->isCapacityMutable()) { + checkLength(capacity); const_svector value; swap(value); if(value.capacity()isImmutable()) - THROW_EXCEPTION2(std::logic_error,"Immutable"); + THROW_EXCEPTION2(std::logic_error, "immutable"); const_svector value; swap(value); - if(length == value.size()) { - // nothing - } else if(length < value.size()) { + + if (length == value.size()) + return; + + checkLength(length); + + if (length < value.size()) { value.slice(0, length); } else { svector mvalue(thaw(value)); @@ -131,8 +145,10 @@ void PVStructureArray::setLength(size_t length) void PVStructureArray::swap(const_svector &other) { - if(this->isImmutable()) - THROW_EXCEPTION2(std::logic_error,"Immutable"); + if (this->isImmutable()) + THROW_EXCEPTION2(std::logic_error, "immutable"); + + // no checkLength call here value.swap(other); } @@ -146,7 +162,10 @@ void PVStructureArray::deserialize(ByteBuffer *pbuffer, DeserializableControl *pcontrol) { svector data(reuse()); - size_t size = SerializeHelper::readSize(pbuffer, pcontrol); + size_t size = this->getArray()->getArraySizeType() == Array::fixed ? + this->getArray()->getMaximumCapacity() : + SerializeHelper::readSize(pbuffer, pcontrol); + data.resize(size); StructureConstPtr structure = structureArray->getStructure(); @@ -175,7 +194,11 @@ void PVStructureArray::serialize(ByteBuffer *pbuffer, const_svector temp(view()); temp.slice(offset, count); - SerializeHelper::writeSize(temp.size(), pbuffer, pflusher); + ArrayConstPtr array = this->getArray(); + if (array->getArraySizeType() != Array::fixed) + SerializeHelper::writeSize(temp.size(), pbuffer, pflusher); + else if (count != array->getMaximumCapacity()) + throw std::length_error("fixed array cannot be partially serialized"); for(size_t i = 0; igetRemaining()<1) diff --git a/src/factory/PVUnionArray.cpp b/src/factory/PVUnionArray.cpp index 4d19a03..dc556cf 100644 --- a/src/factory/PVUnionArray.cpp +++ b/src/factory/PVUnionArray.cpp @@ -25,6 +25,8 @@ namespace epics { namespace pvData { size_t PVUnionArray::append(size_t number) { + checkLength(value.size()+number); + svector data(reuse()); data.resize(data.size()+number); @@ -44,9 +46,11 @@ size_t PVUnionArray::append(size_t number) bool PVUnionArray::remove(size_t offset,size_t number) { - if(number==0) + if (number==0) return true; - else if(offset+number>getLength()) + else if (offset+number>getLength()) + return false; + else if (getArray()->getArraySizeType() == Array::fixed) return false; svector vec(reuse()); @@ -65,6 +69,9 @@ bool PVUnionArray::remove(size_t offset,size_t number) } void PVUnionArray::compress() { + if (getArray()->getArraySizeType() == Array::fixed) + return; + svector vec(reuse()); // TODO: check for first NULL before realloc size_t length = vec.size(); @@ -100,6 +107,7 @@ void PVUnionArray::compress() { void PVUnionArray::setCapacity(size_t capacity) { if(this->isCapacityMutable()) { + checkLength(capacity); const_svector value; swap(value); if(value.capacity()isImmutable()) - THROW_EXCEPTION2(std::logic_error,"Immutable"); + THROW_EXCEPTION2(std::logic_error, "immutable"); const_svector value; swap(value); - if(length == value.size()) { - // nothing - } else if(length < value.size()) { + if (length == value.size()) + return; + + checkLength(length); + + if (length < value.size()) { value.slice(0, length); } else { svector mvalue(thaw(value)); @@ -134,6 +147,8 @@ void PVUnionArray::swap(const_svector &other) if(this->isImmutable()) THROW_EXCEPTION2(std::logic_error,"Immutable"); + // no checkLength call here + value.swap(other); } @@ -146,7 +161,10 @@ void PVUnionArray::deserialize(ByteBuffer *pbuffer, DeserializableControl *pcontrol) { svector data(reuse()); - size_t size = SerializeHelper::readSize(pbuffer, pcontrol); + size_t size = this->getArray()->getArraySizeType() == Array::fixed ? + this->getArray()->getMaximumCapacity() : + SerializeHelper::readSize(pbuffer, pcontrol); + data.resize(size); UnionConstPtr punion = unionArray->getUnion(); @@ -175,7 +193,11 @@ void PVUnionArray::serialize(ByteBuffer *pbuffer, const_svector temp(view()); temp.slice(offset, count); - SerializeHelper::writeSize(temp.size(), pbuffer, pflusher); + ArrayConstPtr array = this->getArray(); + if (array->getArraySizeType() != Array::fixed) + SerializeHelper::writeSize(temp.size(), pbuffer, pflusher); + else if (count != array->getMaximumCapacity()) + throw std::length_error("fixed array cannot be partially serialized"); for(size_t i = 0; igetRemaining()<1) diff --git a/src/pv/pvData.h b/src/pv/pvData.h index 5909ea7..e2e1219 100644 --- a/src/pv/pvData.h +++ b/src/pv/pvData.h @@ -511,6 +511,7 @@ public: protected: PVArray(FieldConstPtr const & field); + void checkLength(size_t length); private: bool capacityMutable; friend class PVDataCreate; @@ -1194,6 +1195,7 @@ public: virtual const_svector view() const { return value; } virtual void swap(const_svector &other); virtual void replace(const const_svector &other) { + checkLength(other.size()); value = other; PVField::postPut(); } @@ -1289,6 +1291,7 @@ public: virtual const_svector view() const { return value; } virtual void swap(const_svector &other); virtual void replace(const const_svector &other) { + checkLength(other.size()); value = other; PVField::postPut(); } diff --git a/src/pv/pvIntrospect.h b/src/pv/pvIntrospect.h index ee08c27..68ca43a 100644 --- a/src/pv/pvIntrospect.h +++ b/src/pv/pvIntrospect.h @@ -387,13 +387,13 @@ public: * Get array size type (i.e. variable/fixed/bounded size array). * @return array size type enum. */ - ArraySizeType getArraySizeType() const; + virtual ArraySizeType getArraySizeType() const = 0; /** * Get maximum capacity of the array. * @return maximum capacity of the array, 0 indicates variable size array. */ - std::size_t getMaximumCapacity() const; + virtual std::size_t getMaximumCapacity() const = 0; protected: /** @@ -541,6 +541,10 @@ public: */ StructureConstPtr getStructure() const {return pstructure;} + virtual ArraySizeType getArraySizeType() const {return Array::variable;} + + virtual std::size_t getMaximumCapacity() const {return 0;} + virtual std::string getID() const; virtual std::ostream& dump(std::ostream& o) const; @@ -578,6 +582,10 @@ public: */ UnionConstPtr getUnion() const {return punion;} + virtual ArraySizeType getArraySizeType() const {return Array::variable;} + + virtual std::size_t getMaximumCapacity() const {return 0;} + virtual std::string getID() const; virtual std::ostream& dump(std::ostream& o) const; diff --git a/testApp/misc/testSerialization.cpp b/testApp/misc/testSerialization.cpp index be4e6ac..f8b216e 100644 --- a/testApp/misc/testSerialization.cpp +++ b/testApp/misc/testSerialization.cpp @@ -714,7 +714,10 @@ void testArraySizeType() { testOk1(3 == s->getFields().size()); serializationFieldTest(s); - serializationTest(getPVDataCreate()->createPVStructure(s)); + +// PVStructurePtr pvs = getPVDataCreate()->createPVStructure(s); +// pvs-> +// serializationTest(pvs); } void testStringCopy() {