Work on error handling. I replaced some asserts with exceptions and also added basic error handling documentation.

This commit is contained in:
David Williams 2013-05-11 10:05:08 +02:00
parent 62d164ef8a
commit ee299a45f0
22 changed files with 213 additions and 90 deletions

View File

@ -0,0 +1,10 @@
**************
Error Handling
**************
Error handling in PolyVox is provided by using the C++ exception mechanism. Exceptions can be thrown for a variety of reasons and your code should be prepared to handle them to prevent your application from crashing.
Most functions in PolyVox will validate their input parameters and throw an exception if the provided values do not meet the function's requirements (which should be specified in the API documentation). However, in certain performance critical cases we choose not to spend time validating the parameters and an exception will not be thrown, though we do still use an assertion if these are enabled.
The most notable example of this is when accessing volume data through the get/setVoxel() functions, as these are designed to be very fast. Validating an input position would require multiple conditional operations which we chose to avoid. Therefore, **accessing a voxel outside of a volume will cause undefined behaviour.** When reading voxels it is safer to use the function getVoxelWithWrapping() as this lets you specify how out-of-bounds voxels should be handled.
In addition to the C++ exception handling mechanism, PolyVox also makes use of assertions to verify the internal state of the library at various points. If you hit an assert in PolyVox then there is a good chance it is a bug in the library, as user errors should have been prevented by throwing an exceptions.

View File

@ -14,6 +14,7 @@ User Guide:
ModifyingTerrain ModifyingTerrain
LevelOfDetail LevelOfDetail
Threading Threading
ErrorHandling
Examples: Examples:

View File

@ -298,7 +298,7 @@ namespace PolyVox
hVal = SixConnectedCost(a, b); hVal = SixConnectedCost(a, b);
break; break;
default: default:
POLYVOX_ASSERT(false, "Invalid case"); POLYVOX_THROW(std::invalid_argument, "Connectivity parameter has an unrecognised value.");
} }
//Sanity checks in debug mode. These can come out eventually, but I //Sanity checks in debug mode. These can come out eventually, but I

View File

@ -34,15 +34,24 @@ namespace PolyVox
template<typename VolumeType, typename IsVoxelTransparentCallback> template<typename VolumeType, typename IsVoxelTransparentCallback>
void calculateAmbientOcclusion(VolumeType* volInput, Array<3, uint8_t>* arrayResult, Region region, float fRayLength, uint8_t uNoOfSamplesPerOutputElement, IsVoxelTransparentCallback isVoxelTransparentCallback) void calculateAmbientOcclusion(VolumeType* volInput, Array<3, uint8_t>* arrayResult, Region region, float fRayLength, uint8_t uNoOfSamplesPerOutputElement, IsVoxelTransparentCallback isVoxelTransparentCallback)
{ {
//Make sure that the size of the volume is an exact multiple of the size of the array.
if(volInput->getWidth() % arrayResult->getDimension(0) != 0)
{
POLYVOX_THROW(std::invalid_argument, "Volume width must be an exact multiple of array width.");
}
if(volInput->getHeight() % arrayResult->getDimension(1) != 0)
{
POLYVOX_THROW(std::invalid_argument, "Volume width must be an exact multiple of array height.");
}
if(volInput->getDepth() % arrayResult->getDimension(2) != 0)
{
POLYVOX_THROW(std::invalid_argument, "Volume width must be an exact multiple of array depth.");
}
uint16_t uRandomUnitVectorIndex = 0; uint16_t uRandomUnitVectorIndex = 0;
uint16_t uRandomVectorIndex = 0; uint16_t uRandomVectorIndex = 0;
uint16_t uIndexIncreament; uint16_t uIndexIncreament;
//Make sure that the size of the volume is an exact multiple of the size of the array.
POLYVOX_ASSERT(volInput->getWidth() % arrayResult->getDimension(0) == 0, "Volume width must be an exact multiple of array width.");
POLYVOX_ASSERT(volInput->getHeight() % arrayResult->getDimension(1) == 0, "Volume height must be an exact multiple of array height.");
POLYVOX_ASSERT(volInput->getDepth() % arrayResult->getDimension(2) == 0, "Volume depth must be an exact multiple of array depth.");
//Our initial indices. It doesn't matter exactly what we set here, but the code below makes //Our initial indices. It doesn't matter exactly what we set here, but the code below makes
//sure they are different for different regions which helps reduce tiling patterns in the results. //sure they are different for different regions which helps reduce tiling patterns in the results.
uRandomUnitVectorIndex += region.getLowerX() + region.getLowerY() + region.getLowerZ(); uRandomUnitVectorIndex += region.getLowerX() + region.getLowerY() + region.getLowerZ();

View File

@ -73,7 +73,11 @@ namespace PolyVox
template <uint32_t noOfDims, typename ElementType> template <uint32_t noOfDims, typename ElementType>
SubArray<noOfDims-1, ElementType> Array<noOfDims, ElementType>::operator[](uint32_t uIndex) SubArray<noOfDims-1, ElementType> Array<noOfDims, ElementType>::operator[](uint32_t uIndex)
{ {
POLYVOX_ASSERT(uIndex < m_pDimensions[0], "Index out of range"); if(uIndex >= m_pDimensions[0])
{
POLYVOX_THROW(std::out_of_range, "Array index out of range");
}
return return
SubArray<noOfDims-1, ElementType>(&m_pElements[uIndex*m_pOffsets[0]], SubArray<noOfDims-1, ElementType>(&m_pElements[uIndex*m_pOffsets[0]],
m_pDimensions+1, m_pOffsets+1); m_pDimensions+1, m_pOffsets+1);
@ -91,7 +95,11 @@ namespace PolyVox
template <uint32_t noOfDims, typename ElementType> template <uint32_t noOfDims, typename ElementType>
const SubArray<noOfDims-1, ElementType> Array<noOfDims, ElementType>::operator[](uint32_t uIndex) const const SubArray<noOfDims-1, ElementType> Array<noOfDims, ElementType>::operator[](uint32_t uIndex) const
{ {
POLYVOX_ASSERT(uIndex < m_pDimensions[0], "Index out of range"); if(uIndex >= m_pDimensions[0])
{
POLYVOX_THROW(std::out_of_range, "Array index out of range");
}
return return
SubArray<noOfDims-1, ElementType>(&m_pElements[uIndex*m_pOffsets[0]], SubArray<noOfDims-1, ElementType>(&m_pElements[uIndex*m_pOffsets[0]],
m_pDimensions+1, m_pOffsets+1); m_pDimensions+1, m_pOffsets+1);
@ -139,7 +147,10 @@ namespace PolyVox
m_uNoOfElements = 1; m_uNoOfElements = 1;
for (uint32_t i = 0; i<noOfDims; i++) for (uint32_t i = 0; i<noOfDims; i++)
{ {
POLYVOX_ASSERT(pDimensions[i] != 0, "Invalid dimension"); if(pDimensions[i] == 0)
{
POLYVOX_THROW(std::out_of_range, "Invalid array dimension");
}
m_uNoOfElements *= pDimensions[i]; m_uNoOfElements *= pDimensions[i];
m_pDimensions[i] = pDimensions[i]; m_pDimensions[i] = pDimensions[i];
@ -186,7 +197,11 @@ namespace PolyVox
template <uint32_t noOfDims, typename ElementType> template <uint32_t noOfDims, typename ElementType>
uint32_t Array<noOfDims, ElementType>::getDimension(uint32_t uDimension) uint32_t Array<noOfDims, ElementType>::getDimension(uint32_t uDimension)
{ {
POLYVOX_ASSERT(uDimension < noOfDims, "Dimension out of range"); if(uDimension >= noOfDims)
{
POLYVOX_THROW(std::out_of_range, "Array dimension out of range");
}
return m_pDimensions[uDimension]; return m_pDimensions[uDimension];
} }
@ -198,14 +213,14 @@ namespace PolyVox
,m_uNoOfElements(0) ,m_uNoOfElements(0)
{ {
//Not implemented //Not implemented
POLYVOX_ASSERT(false, "Not implemented."); POLYVOX_THROW(not_implemented, "This function is not implemented and should never be called!");
} }
template <uint32_t noOfDims, typename ElementType> template <uint32_t noOfDims, typename ElementType>
Array<noOfDims, ElementType>& Array<noOfDims, ElementType>::operator=(const Array<noOfDims, ElementType>& rhs) Array<noOfDims, ElementType>& Array<noOfDims, ElementType>::operator=(const Array<noOfDims, ElementType>& rhs)
{ {
//Not implemented //Not implemented
POLYVOX_ASSERT(false, "Not implemented."); POLYVOX_THROW(not_implemented, "This function is not implemented and should never be called!");
return *this; return *this;
} }
@ -251,14 +266,22 @@ namespace PolyVox
template <typename ElementType> template <typename ElementType>
ElementType& Array<1, ElementType>::operator[] (uint32_t uIndex) ElementType& Array<1, ElementType>::operator[] (uint32_t uIndex)
{ {
POLYVOX_ASSERT(uIndex < m_pDimensions[0], "Index out of range"); if(uIndex >= m_pDimensions[0])
{
POLYVOX_THROW(std::out_of_range, "Array index out of range");
}
return m_pElements[uIndex]; return m_pElements[uIndex];
} }
template <typename ElementType> template <typename ElementType>
const ElementType& Array<1, ElementType>::operator[] (uint32_t uIndex) const const ElementType& Array<1, ElementType>::operator[] (uint32_t uIndex) const
{ {
POLYVOX_ASSERT(uIndex < m_pDimensions[0], "Index out of range"); if(uIndex >= m_pDimensions[0])
{
POLYVOX_THROW(std::out_of_range, "Array index out of range");
}
return m_pElements[uIndex]; return m_pElements[uIndex];
} }
@ -307,14 +330,14 @@ namespace PolyVox
,m_pDimensions(0) ,m_pDimensions(0)
{ {
//Not implemented //Not implemented
POLYVOX_ASSERT(false, "Not implemented."); POLYVOX_THROW(not_implemented, "This function is not implemented and should never be called!");
} }
template <typename ElementType> template <typename ElementType>
Array<1, ElementType>& Array<1, ElementType>::operator=(const Array<1, ElementType>& rhs) Array<1, ElementType>& Array<1, ElementType>::operator=(const Array<1, ElementType>& rhs)
{ {
//Not implemented //Not implemented
POLYVOX_ASSERT(false, "Not implemented."); POLYVOX_THROW(not_implemented, "This function is not implemented and should never be called!");
return *this; return *this;
} }

View File

@ -45,7 +45,7 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
BaseVolume<VoxelType>::BaseVolume(const BaseVolume<VoxelType>& /*rhs*/) BaseVolume<VoxelType>::BaseVolume(const BaseVolume<VoxelType>& /*rhs*/)
{ {
POLYVOX_ASSERT(false, "Copy constructor not implemented."); // See function comment above. POLYVOX_THROW(not_implemented, "Volume copy constructor not implemented for performance reasons.");
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -59,14 +59,14 @@ namespace PolyVox
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// This function should never be called. Copying volumes by value would be expensive, and we want to prevent users from doing /// This function should never be called. Copying volumes by value would be expensive, and we want to prevent users from doing
/// it by accident (such as when passing them as paramenters to functions). That said, there are times when you really do want to /// it by accident (such as when passing them as paramenters to functions). That said, there are times when you really do want to
/// make a copy of a volume and in this case you should look at the Volumeresampler. /// make a copy of a volume and in this case you should look at the VolumeResampler.
/// ///
/// \sa VolumeResampler /// \sa VolumeResampler
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType> template <typename VoxelType>
BaseVolume<VoxelType>& BaseVolume<VoxelType>::operator=(const BaseVolume<VoxelType>& /*rhs*/) BaseVolume<VoxelType>& BaseVolume<VoxelType>::operator=(const BaseVolume<VoxelType>& /*rhs*/)
{ {
POLYVOX_ASSERT(false, "Assignment operator not implemented."); // See function comment above. POLYVOX_THROW(not_implemented, "Volume assignment operator not implemented for performance reasons.");
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -162,7 +162,7 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
VoxelType BaseVolume<VoxelType>::getVoxel(int32_t /*uXPos*/, int32_t /*uYPos*/, int32_t /*uZPos*/) const VoxelType BaseVolume<VoxelType>::getVoxel(int32_t /*uXPos*/, int32_t /*uYPos*/, int32_t /*uZPos*/) const
{ {
POLYVOX_ASSERT(false, "You should never call the base class version of this function."); POLYVOX_THROW(not_implemented, "You should never call the base class version of this function.");
return VoxelType(); return VoxelType();
} }
@ -173,7 +173,7 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
VoxelType BaseVolume<VoxelType>::getVoxel(const Vector3DInt32& /*v3dPos*/) const VoxelType BaseVolume<VoxelType>::getVoxel(const Vector3DInt32& /*v3dPos*/) const
{ {
POLYVOX_ASSERT(false, "You should never call the base class version of this function."); POLYVOX_THROW(not_implemented, "You should never call the base class version of this function.");
return VoxelType(); return VoxelType();
} }
@ -186,7 +186,7 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
VoxelType BaseVolume<VoxelType>::getVoxelAt(int32_t /*uXPos*/, int32_t /*uYPos*/, int32_t /*uZPos*/) const VoxelType BaseVolume<VoxelType>::getVoxelAt(int32_t /*uXPos*/, int32_t /*uYPos*/, int32_t /*uZPos*/) const
{ {
POLYVOX_ASSERT(false, "You should never call the base class version of this function."); POLYVOX_THROW(not_implemented, "You should never call the base class version of this function.");
return VoxelType(); return VoxelType();
} }
@ -197,7 +197,7 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
VoxelType BaseVolume<VoxelType>::getVoxelAt(const Vector3DInt32& /*v3dPos*/) const VoxelType BaseVolume<VoxelType>::getVoxelAt(const Vector3DInt32& /*v3dPos*/) const
{ {
POLYVOX_ASSERT(false, "You should never call the base class version of this function."); POLYVOX_THROW(not_implemented, "You should never call the base class version of this function.");
return VoxelType(); return VoxelType();
} }
@ -210,7 +210,7 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
VoxelType BaseVolume<VoxelType>::getVoxelWithWrapping(int32_t /*uXPos*/, int32_t /*uYPos*/, int32_t /*uZPos*/, WrapMode /*eWrapMode*/, VoxelType /*tBorder*/) const VoxelType BaseVolume<VoxelType>::getVoxelWithWrapping(int32_t /*uXPos*/, int32_t /*uYPos*/, int32_t /*uZPos*/, WrapMode /*eWrapMode*/, VoxelType /*tBorder*/) const
{ {
POLYVOX_ASSERT(false, "You should never call the base class version of this function."); POLYVOX_THROW(not_implemented, "You should never call the base class version of this function.");
return VoxelType(); return VoxelType();
} }
@ -221,7 +221,7 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
VoxelType BaseVolume<VoxelType>::getVoxelWithWrapping(const Vector3DInt32& /*v3dPos*/, WrapMode /*eWrapMode*/, VoxelType /*tBorder*/) const VoxelType BaseVolume<VoxelType>::getVoxelWithWrapping(const Vector3DInt32& /*v3dPos*/, WrapMode /*eWrapMode*/, VoxelType /*tBorder*/) const
{ {
POLYVOX_ASSERT(false, "You should never call the base class version of this function."); POLYVOX_THROW(not_implemented, "You should never call the base class version of this function.");
return VoxelType(); return VoxelType();
} }
@ -244,7 +244,7 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
bool BaseVolume<VoxelType>::setVoxelAt(int32_t /*uXPos*/, int32_t /*uYPos*/, int32_t /*uZPos*/, VoxelType /*tValue*/) bool BaseVolume<VoxelType>::setVoxelAt(int32_t /*uXPos*/, int32_t /*uYPos*/, int32_t /*uZPos*/, VoxelType /*tValue*/)
{ {
POLYVOX_ASSERT(false, "You should never call the base class version of this function."); POLYVOX_THROW(not_implemented, "You should never call the base class version of this function.");
return false; return false;
} }
@ -256,7 +256,7 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
bool BaseVolume<VoxelType>::setVoxelAt(const Vector3DInt32& /*v3dPos*/, VoxelType /*tValue*/) bool BaseVolume<VoxelType>::setVoxelAt(const Vector3DInt32& /*v3dPos*/, VoxelType /*tValue*/)
{ {
POLYVOX_ASSERT(false, "You should never call the base class version of this function."); POLYVOX_THROW(not_implemented, "You should never call the base class version of this function.");
return false; return false;
} }

View File

@ -375,7 +375,7 @@ namespace PolyVox
default: default:
{ {
//Should never happen //Should never happen
POLYVOX_ASSERT(false, "Invalid case."); POLYVOX_THROW(std::invalid_argument, "Wrap mode parameter has an unrecognised value.");
return VoxelType(); return VoxelType();
} }
} }

View File

@ -37,24 +37,28 @@ namespace PolyVox
public: public:
VoxelType getVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos) const VoxelType getVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos) const
{ {
// PolyVox does not throw an exception when a voxel is out of range. Please see 'Error Handling' in the User Manual.
POLYVOX_ASSERT(m_regValid.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)), "Position is outside valid region"); POLYVOX_ASSERT(m_regValid.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)), "Position is outside valid region");
return m_pVolume.getVoxelAt(uXPos, uYPos, uZPos); return m_pVolume.getVoxelAt(uXPos, uYPos, uZPos);
} }
VoxelType getVoxelAt(const Vector3DInt32& v3dPos) const VoxelType getVoxelAt(const Vector3DInt32& v3dPos) const
{ {
// PolyVox does not throw an exception when a voxel is out of range. Please see 'Error Handling' in the User Manual.
POLYVOX_ASSERT(m_regValid.containsPoint(v3dPos), "Position is outside valid region"); POLYVOX_ASSERT(m_regValid.containsPoint(v3dPos), "Position is outside valid region");
return getVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ()); return getVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ());
} }
void setVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue) const void setVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue) const
{ {
// PolyVox does not throw an exception when a voxel is out of range. Please see 'Error Handling' in the User Manual.
POLYVOX_ASSERT(m_regValid.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)), "Position is outside valid region"); POLYVOX_ASSERT(m_regValid.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)), "Position is outside valid region");
m_pVolume.setVoxelAtConst(uXPos, uYPos, uZPos, tValue); m_pVolume.setVoxelAtConst(uXPos, uYPos, uZPos, tValue);
} }
void setVoxelAt(const Vector3DInt32& v3dPos, VoxelType tValue) const void setVoxelAt(const Vector3DInt32& v3dPos, VoxelType tValue) const
{ {
// PolyVox does not throw an exception when a voxel is out of range. Please see 'Error Handling' in the User Manual.
POLYVOX_ASSERT(m_regValid.containsPoint(v3dPos), "Position is outside valid region"); POLYVOX_ASSERT(m_regValid.containsPoint(v3dPos), "Position is outside valid region");
setVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tValue); setVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tValue);
} }

View File

@ -220,9 +220,9 @@ namespace PolyVox
} }
} }
// If we exit the loop here then apparently all the slots were full but none of them matched. I don't think // If we exit the loop here then apparently all the slots were full but none of them matched.
// this can happen so let's put an assert to make sure. If you hit this assert then please report it to us! // This shouldn't ever happen, so if it does it is probably a bug in PolyVox. Please report it to us!
POLYVOX_ASSERT(false, "All slots full but no matches."); POLYVOX_THROW(std::runtime_error, "All slots full but no matches during cubic surface extraction. This is probably a bug in PolyVox");
return -1; //Should never happen. return -1; //Should never happen.
} }

View File

@ -60,10 +60,10 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
VoxelType Block<VoxelType>::getVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos) const VoxelType Block<VoxelType>::getVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos) const
{ {
// This is internal code not directly called by the user. For efficiency we assert rather than throwing.
POLYVOX_ASSERT(uXPos < m_uSideLength, "Supplied position is outside of the block"); POLYVOX_ASSERT(uXPos < m_uSideLength, "Supplied position is outside of the block");
POLYVOX_ASSERT(uYPos < m_uSideLength, "Supplied position is outside of the block"); POLYVOX_ASSERT(uYPos < m_uSideLength, "Supplied position is outside of the block");
POLYVOX_ASSERT(uZPos < m_uSideLength, "Supplied position is outside of the block"); POLYVOX_ASSERT(uZPos < m_uSideLength, "Supplied position is outside of the block");
POLYVOX_ASSERT(m_tUncompressedData, "No uncompressed data - block must be decompressed before accessing voxels."); POLYVOX_ASSERT(m_tUncompressedData, "No uncompressed data - block must be decompressed before accessing voxels.");
return m_tUncompressedData return m_tUncompressedData
@ -83,10 +83,10 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
void Block<VoxelType>::setVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tValue) void Block<VoxelType>::setVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tValue)
{ {
// This is internal code not directly called by the user. For efficiency we assert rather than throwing.
POLYVOX_ASSERT(uXPos < m_uSideLength, "Supplied position is outside of the block"); POLYVOX_ASSERT(uXPos < m_uSideLength, "Supplied position is outside of the block");
POLYVOX_ASSERT(uYPos < m_uSideLength, "Supplied position is outside of the block"); POLYVOX_ASSERT(uYPos < m_uSideLength, "Supplied position is outside of the block");
POLYVOX_ASSERT(uZPos < m_uSideLength, "Supplied position is outside of the block"); POLYVOX_ASSERT(uZPos < m_uSideLength, "Supplied position is outside of the block");
POLYVOX_ASSERT(m_tUncompressedData, "No uncompressed data - block must be decompressed before accessing voxels."); POLYVOX_ASSERT(m_tUncompressedData, "No uncompressed data - block must be decompressed before accessing voxels.");
m_tUncompressedData m_tUncompressedData
@ -108,9 +108,6 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
void Block<VoxelType>::initialise(uint16_t uSideLength) void Block<VoxelType>::initialise(uint16_t uSideLength)
{ {
//Debug mode validation
POLYVOX_ASSERT(isPowerOf2(uSideLength), "Block side length must be a power of two.");
//Release mode validation //Release mode validation
if(!isPowerOf2(uSideLength)) if(!isPowerOf2(uSideLength))
{ {
@ -141,8 +138,16 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
void Block<VoxelType>::compress(Compressor* pCompressor) void Block<VoxelType>::compress(Compressor* pCompressor)
{ {
POLYVOX_ASSERT(pCompressor, "Compressor is not valid"); if(m_bIsCompressed)
POLYVOX_ASSERT(m_bIsCompressed == false, "Attempted to compress block which is already flagged as compressed."); {
POLYVOX_THROW(invalid_operation, "Attempted to compress block which is already flagged as compressed.");
}
if(!pCompressor)
{
POLYVOX_THROW(std::invalid_argument, "A valid compressor must be provided");
}
POLYVOX_ASSERT(m_tUncompressedData != 0, "No uncompressed data is present."); POLYVOX_ASSERT(m_tUncompressedData != 0, "No uncompressed data is present.");
//If the uncompressed data hasn't actually been //If the uncompressed data hasn't actually been
@ -212,8 +217,16 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
void Block<VoxelType>::uncompress(Compressor* pCompressor) void Block<VoxelType>::uncompress(Compressor* pCompressor)
{ {
POLYVOX_ASSERT(pCompressor, "Compressor is not valid"); if(!m_bIsCompressed)
POLYVOX_ASSERT(m_bIsCompressed == true, "Attempted to uncompress block which is not flagged as compressed."); {
POLYVOX_THROW(invalid_operation, "Attempted to uncompress block which is not flagged as compressed.");
}
if(!pCompressor)
{
POLYVOX_THROW(std::invalid_argument, "A valid compressor must be provided");
}
POLYVOX_ASSERT(m_tUncompressedData == 0, "Uncompressed data already exists."); POLYVOX_ASSERT(m_tUncompressedData == 0, "Uncompressed data already exists.");
m_tUncompressedData = new VoxelType[m_uSideLength * m_uSideLength * m_uSideLength]; m_tUncompressedData = new VoxelType[m_uSideLength * m_uSideLength * m_uSideLength];

View File

@ -26,9 +26,10 @@ freely, subject to the following restrictions:
#include "PolyVoxCore/Impl/Config.h" #include "PolyVoxCore/Impl/Config.h"
#include <cstdlib> //For std::exit #include <cstdlib> // For std::exit
#include <iostream> //For std::cerr #include <iostream> // For std::cerr
#include <stdexcept> #include <stdexcept>
#include <string.h> // Exception constuctors take strings.
#if defined(_MSC_VER) #if defined(_MSC_VER)
// In Visual Studio we can use this function to go into the debugger. // In Visual Studio we can use this function to go into the debugger.
@ -148,4 +149,32 @@ freely, subject to the following restrictions:
getThrowHandler()((except), __FILE__, __LINE__) getThrowHandler()((except), __FILE__, __LINE__)
#endif #endif
namespace PolyVox
{
/// A general purpose exception to indicate that an operation cannot be peformed.
class invalid_operation : public std::logic_error
{
public:
explicit invalid_operation(const std::string& message)
: logic_error(message.c_str()) {}
explicit invalid_operation(const char *message)
: logic_error(message) {}
};
/// Thrown to indicate that a function is deliberatly not implmented. For example, perhaps you called a function
/// in a base class whereas you are supposed to use a derived class which implements the function, or perhaps the
/// function is not defined for a particular template parameter. It may be that the function is required to
/// compile sucessfully but it should not be called.
class not_implemented : public std::logic_error
{
public:
explicit not_implemented(const std::string& message)
: logic_error(message.c_str()) {}
explicit not_implemented(const char *message)
: logic_error(message) {}
};
}
#endif //__PolyVox_ErrorHandling_H__ #endif //__PolyVox_ErrorHandling_H__

View File

@ -28,7 +28,11 @@ namespace PolyVox
template <uint32_t noOfDims, typename ElementType> template <uint32_t noOfDims, typename ElementType>
SubArray<noOfDims-1, ElementType> SubArray<noOfDims, ElementType>::operator[](uint32_t uIndex) SubArray<noOfDims-1, ElementType> SubArray<noOfDims, ElementType>::operator[](uint32_t uIndex)
{ {
POLYVOX_ASSERT(uIndex < m_pDimensions[0], "Index out of range"); if(uIndex >= m_pDimensions[0])
{
POLYVOX_THROW(std::out_of_range, "Array index out of range");
}
return return
SubArray<noOfDims-1, ElementType>(&m_pElements[uIndex*m_pOffsets[0]], SubArray<noOfDims-1, ElementType>(&m_pElements[uIndex*m_pOffsets[0]],
m_pDimensions+1, m_pOffsets+1); m_pDimensions+1, m_pOffsets+1);
@ -37,7 +41,11 @@ namespace PolyVox
template <uint32_t noOfDims, typename ElementType> template <uint32_t noOfDims, typename ElementType>
const SubArray<noOfDims-1, ElementType> SubArray<noOfDims, ElementType>::operator[](uint32_t uIndex) const const SubArray<noOfDims-1, ElementType> SubArray<noOfDims, ElementType>::operator[](uint32_t uIndex) const
{ {
POLYVOX_ASSERT(uIndex < m_pDimensions[0], "Index out of range"); if(uIndex >= m_pDimensions[0])
{
POLYVOX_THROW(std::out_of_range, "Array index out of range");
}
return return
SubArray<noOfDims-1, ElementType>(&m_pElements[uIndex*m_pOffsets[0]], SubArray<noOfDims-1, ElementType>(&m_pElements[uIndex*m_pOffsets[0]],
m_pDimensions+1, m_pOffsets+1); m_pDimensions+1, m_pOffsets+1);
@ -56,14 +64,22 @@ namespace PolyVox
template <typename ElementType> template <typename ElementType>
ElementType& SubArray<1, ElementType>::operator[] (uint32_t uIndex) ElementType& SubArray<1, ElementType>::operator[] (uint32_t uIndex)
{ {
POLYVOX_ASSERT(uIndex < m_pDimensions[0], "Index out of range"); if(uIndex >= m_pDimensions[0])
{
POLYVOX_THROW(std::out_of_range, "Array index out of range");
}
return m_pElements[uIndex]; return m_pElements[uIndex];
} }
template <typename ElementType> template <typename ElementType>
const ElementType& SubArray<1, ElementType>::operator[] (uint32_t uIndex) const const ElementType& SubArray<1, ElementType>::operator[] (uint32_t uIndex) const
{ {
POLYVOX_ASSERT(uIndex < m_pDimensions[0], "Index out of range"); if(uIndex >= m_pDimensions[0])
{
POLYVOX_THROW(std::out_of_range, "Array index out of range");
}
return m_pElements[uIndex]; return m_pElements[uIndex];
} }

View File

@ -31,6 +31,7 @@ namespace PolyVox
const Type& v0,const Type& v1, const Type& v0,const Type& v1,
const float x) const float x)
{ {
//This function is called frequently and is very short, so assert rather than exceptions.
POLYVOX_ASSERT((x >= 0.0f) && (x <= 1.0f), "Interpolation input out of 0.0 to 1.0 range."); POLYVOX_ASSERT((x >= 0.0f) && (x <= 1.0f), "Interpolation input out of 0.0 to 1.0 range.");
//Interpolate along X //Interpolate along X
@ -44,6 +45,7 @@ namespace PolyVox
const Type& v00,const Type& v10,const Type& v01,const Type& v11, const Type& v00,const Type& v10,const Type& v01,const Type& v11,
const float x, const float y) const float x, const float y)
{ {
//This function is called frequently and is very short, so assert rather than exceptions.
POLYVOX_ASSERT((x >= 0.0f) && (y >= 0.0f) && POLYVOX_ASSERT((x >= 0.0f) && (y >= 0.0f) &&
(x <= 1.0f) && (y <= 1.0f), "Interpolation input out of 0.0 to 1.0 range."); (x <= 1.0f) && (y <= 1.0f), "Interpolation input out of 0.0 to 1.0 range.");
@ -63,6 +65,7 @@ namespace PolyVox
const Type& v001,const Type& v101,const Type& v011,const Type& v111, const Type& v001,const Type& v101,const Type& v011,const Type& v111,
const float x, const float y, const float z) const float x, const float y, const float z)
{ {
//This function is called frequently and is very short, so assert rather than exceptions.
POLYVOX_ASSERT((x >= 0.0f) && (y >= 0.0f) && (z >= 0.0f) && POLYVOX_ASSERT((x >= 0.0f) && (y >= 0.0f) && (z >= 0.0f) &&
(x <= 1.0f) && (y <= 1.0f) && (z <= 1.0f), "Interpolation input out of 0.0 to 1.0 range."); (x <= 1.0f) && (y <= 1.0f) && (z <= 1.0f), "Interpolation input out of 0.0 to 1.0 range.");

View File

@ -90,7 +90,7 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
LargeVolume<VoxelType>::LargeVolume(const LargeVolume<VoxelType>& /*rhs*/) LargeVolume<VoxelType>::LargeVolume(const LargeVolume<VoxelType>& /*rhs*/)
{ {
POLYVOX_ASSERT(false, "Copy constructor not implemented."); // See function comment above. POLYVOX_THROW(not_implemented, "Volume copy constructor not implemented for performance reasons.");
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -112,7 +112,7 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
LargeVolume<VoxelType>& LargeVolume<VoxelType>::operator=(const LargeVolume<VoxelType>& /*rhs*/) LargeVolume<VoxelType>& LargeVolume<VoxelType>::operator=(const LargeVolume<VoxelType>& /*rhs*/)
{ {
POLYVOX_ASSERT(false, "Assignment operator not implemented."); // See function comment above. POLYVOX_THROW(not_implemented, "Volume assignment operator not implemented for performance reasons.");
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -124,6 +124,7 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
VoxelType LargeVolume<VoxelType>::getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos) const VoxelType LargeVolume<VoxelType>::getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos) const
{ {
// PolyVox does not throw an exception when a voxel is out of range. Please see 'Error Handling' in the User Manual.
POLYVOX_ASSERT(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)), "Position is outside valid region"); POLYVOX_ASSERT(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)), "Position is outside valid region");
const int32_t blockX = uXPos >> m_uBlockSideLengthPower; const int32_t blockX = uXPos >> m_uBlockSideLengthPower;
@ -228,7 +229,7 @@ namespace PolyVox
default: default:
{ {
//Should never happen //Should never happen
POLYVOX_ASSERT(false, "Invlaid case."); POLYVOX_THROW(std::invalid_argument, "Wrap mode parameter has an unrecognised value.");
return VoxelType(); return VoxelType();
} }
} }
@ -282,6 +283,7 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
bool LargeVolume<VoxelType>::setVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue) bool LargeVolume<VoxelType>::setVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue)
{ {
// PolyVox does not throw an exception when a voxel is out of range. Please see 'Error Handling' in the User Manual.
POLYVOX_ASSERT(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)), "Position is outside valid region"); POLYVOX_ASSERT(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)), "Position is outside valid region");
const int32_t blockX = uXPos >> m_uBlockSideLengthPower; const int32_t blockX = uXPos >> m_uBlockSideLengthPower;
@ -446,12 +448,7 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
void LargeVolume<VoxelType>::initialise(const Region& regValidRegion, uint16_t uBlockSideLength) void LargeVolume<VoxelType>::initialise(const Region& regValidRegion, uint16_t uBlockSideLength)
{ {
//Debug mode validation //Validate parameters
POLYVOX_ASSERT(uBlockSideLength > 0, "Block side length cannot be zero.");
POLYVOX_ASSERT(isPowerOf2(uBlockSideLength), "Block side length must be a power of two.");
POLYVOX_ASSERT(m_pCompressor, "You must provide a compressor for the LargeVolume to use.");
//Release mode validation
if(uBlockSideLength == 0) if(uBlockSideLength == 0)
{ {
POLYVOX_THROW(std::invalid_argument, "Block side length cannot be zero."); POLYVOX_THROW(std::invalid_argument, "Block side length cannot be zero.");

View File

@ -143,7 +143,7 @@ namespace PolyVox
}*/ }*/
//Need to think what effect this has on any existing iterators. //Need to think what effect this has on any existing iterators.
POLYVOX_ASSERT(false, "This function cnnot be used on LargeVolume samplers."); POLYVOX_THROW(not_implemented, "This function cannot be used on LargeVolume samplers.");
return false; return false;
} }

View File

@ -39,14 +39,15 @@ namespace PolyVox
,m_uKernelSize(uKernelSize) ,m_uKernelSize(uKernelSize)
{ {
//Kernel size must be at least three //Kernel size must be at least three
POLYVOX_ASSERT(m_uKernelSize >= 3, "Kernel size must be at least three"); if(m_uKernelSize < 3)
m_uKernelSize = std::max(m_uKernelSize, static_cast<uint32_t>(3)); //For release builds {
POLYVOX_THROW(std::invalid_argument, "Kernel size must be at least three");
}
//Kernel size must be odd //Kernel size must be odd
POLYVOX_ASSERT(m_uKernelSize % 2 == 1, "Kernel size must be odd"); if(m_uKernelSize % 2 == 0)
if(m_uKernelSize % 2 == 0) //For release builds
{ {
m_uKernelSize++; POLYVOX_THROW(std::invalid_argument, "Kernel size must be odd");
} }
} }

View File

@ -47,7 +47,7 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
RawVolume<VoxelType>::RawVolume(const RawVolume<VoxelType>& /*rhs*/) RawVolume<VoxelType>::RawVolume(const RawVolume<VoxelType>& /*rhs*/)
{ {
POLYVOX_ASSERT(false, "Copy constructor not implemented."); // See function comment above. POLYVOX_THROW(not_implemented, "Volume copy constructor not implemented for performance reasons.");
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -70,7 +70,7 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
RawVolume<VoxelType>& RawVolume<VoxelType>::operator=(const RawVolume<VoxelType>& /*rhs*/) RawVolume<VoxelType>& RawVolume<VoxelType>::operator=(const RawVolume<VoxelType>& /*rhs*/)
{ {
POLYVOX_ASSERT(false, "Assignment operator not implemented."); // See function comment above. POLYVOX_THROW(not_implemented, "Volume assignment operator not implemented for performance reasons.");
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -82,6 +82,7 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
VoxelType RawVolume<VoxelType>::getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos) const VoxelType RawVolume<VoxelType>::getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos) const
{ {
// PolyVox does not throw an exception when a voxel is out of range. Please see 'Error Handling' in the User Manual.
POLYVOX_ASSERT(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)), "Position is outside valid region"); POLYVOX_ASSERT(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)), "Position is outside valid region");
const Vector3DInt32& v3dLowerCorner = this->m_regValidRegion.getLowerCorner(); const Vector3DInt32& v3dLowerCorner = this->m_regValidRegion.getLowerCorner();
@ -186,7 +187,7 @@ namespace PolyVox
default: default:
{ {
//Should never happen //Should never happen
POLYVOX_ASSERT(false, "Invalid case."); POLYVOX_THROW(std::invalid_argument, "Wrap mode parameter has an unrecognised value.");
return VoxelType(); return VoxelType();
} }
} }
@ -254,10 +255,18 @@ namespace PolyVox
{ {
this->m_regValidRegion = regValidRegion; this->m_regValidRegion = regValidRegion;
//Ensure dimensions of the specified Region are valid if(this->getWidth() <= 0)
POLYVOX_ASSERT(this->getWidth() > 0, "Volume width must be greater than zero."); {
POLYVOX_ASSERT(this->getHeight() > 0, "Volume width must be greater than zero."); POLYVOX_THROW(std::invalid_argument, "Volume width must be greater than zero.");
POLYVOX_ASSERT(this->getDepth() > 0, "Volume width must be greater than zero."); }
if(this->getHeight() <= 0)
{
POLYVOX_THROW(std::invalid_argument, "Volume height must be greater than zero.");
}
if(this->getDepth() <= 0)
{
POLYVOX_THROW(std::invalid_argument, "Volume depth must be greater than zero.");
}
//Create the data //Create the data
m_pData = new VoxelType[this->getWidth() * this->getHeight()* this->getDepth()]; m_pData = new VoxelType[this->getWidth() * this->getHeight()* this->getDepth()];

View File

@ -48,7 +48,7 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
SimpleVolume<VoxelType>::SimpleVolume(const SimpleVolume<VoxelType>& /*rhs*/) SimpleVolume<VoxelType>::SimpleVolume(const SimpleVolume<VoxelType>& /*rhs*/)
{ {
POLYVOX_ASSERT(false, "Copy constructor not implemented."); // See function comment above. POLYVOX_THROW(not_implemented, "Volume copy constructor not implemented for performance reasons.");
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -70,7 +70,7 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
SimpleVolume<VoxelType>& SimpleVolume<VoxelType>::operator=(const SimpleVolume<VoxelType>& /*rhs*/) SimpleVolume<VoxelType>& SimpleVolume<VoxelType>::operator=(const SimpleVolume<VoxelType>& /*rhs*/)
{ {
POLYVOX_ASSERT(false, "Assignment operator not implemented."); // See function comment above. POLYVOX_THROW(not_implemented, "Volume assignment operator not implemented for performance reasons.");
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -82,6 +82,7 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
VoxelType SimpleVolume<VoxelType>::getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos) const VoxelType SimpleVolume<VoxelType>::getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos) const
{ {
// PolyVox does not throw an exception when a voxel is out of range. Please see 'Error Handling' in the User Manual.
POLYVOX_ASSERT(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)), "Position is outside valid region"); POLYVOX_ASSERT(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)), "Position is outside valid region");
const int32_t blockX = uXPos >> m_uBlockSideLengthPower; const int32_t blockX = uXPos >> m_uBlockSideLengthPower;
@ -186,7 +187,7 @@ namespace PolyVox
default: default:
{ {
//Should never happen //Should never happen
POLYVOX_ASSERT(false, "Invalid case."); POLYVOX_THROW(std::invalid_argument, "Wrap mode parameter has an unrecognised value.");
return VoxelType(); return VoxelType();
} }
} }
@ -212,6 +213,7 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
bool SimpleVolume<VoxelType>::setVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue) bool SimpleVolume<VoxelType>::setVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue)
{ {
// PolyVox does not throw an exception when a voxel is out of range. Please see 'Error Handling' in the User Manual.
POLYVOX_ASSERT(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)), "Position is outside valid region"); POLYVOX_ASSERT(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)), "Position is outside valid region");
const int32_t blockX = uXPos >> m_uBlockSideLengthPower; const int32_t blockX = uXPos >> m_uBlockSideLengthPower;
@ -247,11 +249,6 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
void SimpleVolume<VoxelType>::initialise(const Region& regValidRegion, uint16_t uBlockSideLength) void SimpleVolume<VoxelType>::initialise(const Region& regValidRegion, uint16_t uBlockSideLength)
{ {
//Debug mode validation
POLYVOX_ASSERT(uBlockSideLength >= 8, "Block side length should be at least 8");
POLYVOX_ASSERT(uBlockSideLength <= 256, "Block side length should not be more than 256");
POLYVOX_ASSERT(isPowerOf2(uBlockSideLength), "Block side length must be a power of two.");
//Release mode validation //Release mode validation
if(uBlockSideLength < 8) if(uBlockSideLength < 8)
{ {

View File

@ -52,10 +52,10 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
VoxelType SimpleVolume<VoxelType>::Block::getVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos) const VoxelType SimpleVolume<VoxelType>::Block::getVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos) const
{ {
// This is internal code not directly called by the user. For efficiency we assert rather than throwing.
POLYVOX_ASSERT(uXPos < m_uSideLength, "Position is outside of the block."); POLYVOX_ASSERT(uXPos < m_uSideLength, "Position is outside of the block.");
POLYVOX_ASSERT(uYPos < m_uSideLength, "Position is outside of the block."); POLYVOX_ASSERT(uYPos < m_uSideLength, "Position is outside of the block.");
POLYVOX_ASSERT(uZPos < m_uSideLength, "Position is outside of the block."); POLYVOX_ASSERT(uZPos < m_uSideLength, "Position is outside of the block.");
POLYVOX_ASSERT(m_tUncompressedData, "No uncompressed data available"); POLYVOX_ASSERT(m_tUncompressedData, "No uncompressed data available");
return m_tUncompressedData return m_tUncompressedData
@ -75,10 +75,10 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
void SimpleVolume<VoxelType>::Block::setVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tValue) void SimpleVolume<VoxelType>::Block::setVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tValue)
{ {
// This is internal code not directly called by the user. For efficiency we assert rather than throwing.
POLYVOX_ASSERT(uXPos < m_uSideLength, "Position is outside of the block."); POLYVOX_ASSERT(uXPos < m_uSideLength, "Position is outside of the block.");
POLYVOX_ASSERT(uYPos < m_uSideLength, "Position is outside of the block."); POLYVOX_ASSERT(uYPos < m_uSideLength, "Position is outside of the block.");
POLYVOX_ASSERT(uZPos < m_uSideLength, "Position is outside of the block."); POLYVOX_ASSERT(uZPos < m_uSideLength, "Position is outside of the block.");
POLYVOX_ASSERT(m_tUncompressedData, "No uncompressed data available"); POLYVOX_ASSERT(m_tUncompressedData, "No uncompressed data available");
m_tUncompressedData m_tUncompressedData
@ -105,9 +105,6 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
void SimpleVolume<VoxelType>::Block::initialise(uint16_t uSideLength) void SimpleVolume<VoxelType>::Block::initialise(uint16_t uSideLength)
{ {
//Debug mode validation
POLYVOX_ASSERT(isPowerOf2(uSideLength), "Block side length must be a power of two.");
//Release mode validation //Release mode validation
if(!isPowerOf2(uSideLength)) if(!isPowerOf2(uSideLength))
{ {

View File

@ -414,7 +414,11 @@ namespace PolyVox
template <uint32_t Size, typename StorageType, typename OperationType> template <uint32_t Size, typename StorageType, typename OperationType>
inline StorageType Vector<Size, StorageType, OperationType>::getElement(uint32_t index) const inline StorageType Vector<Size, StorageType, OperationType>::getElement(uint32_t index) const
{ {
POLYVOX_ASSERT(index < Size, "Attempted to access invalid vector element."); if(index >= Size)
{
POLYVOX_THROW(std::out_of_range, "Attempted to access invalid vector element.");
}
return m_tElements[index]; return m_tElements[index];
} }
@ -465,7 +469,11 @@ namespace PolyVox
template <uint32_t Size, typename StorageType, typename OperationType> template <uint32_t Size, typename StorageType, typename OperationType>
inline void Vector<Size, StorageType, OperationType>::setElement(uint32_t index, StorageType tValue) inline void Vector<Size, StorageType, OperationType>::setElement(uint32_t index, StorageType tValue)
{ {
POLYVOX_ASSERT(index < Size, "Attempted to access invalid vector element."); if(index >= Size)
{
POLYVOX_THROW(std::out_of_range, "Attempted to access invalid vector element.");
}
m_tElements[index] = tValue; m_tElements[index] = tValue;
} }
@ -645,10 +653,17 @@ namespace PolyVox
inline void Vector<Size, StorageType, OperationType>::normalise(void) inline void Vector<Size, StorageType, OperationType>::normalise(void)
{ {
float fLength = this->length(); float fLength = this->length();
if(fLength <= 0.0)
{
POLYVOX_THROW(invalid_operation, "Cannot normalise a vector with a length of zero");
}
for(uint32_t ct = 0; ct < Size; ++ct) for(uint32_t ct = 0; ct < Size; ++ct)
{ {
// Standard float rules apply for divide-by-zero // Standard float rules apply for divide-by-zero
m_tElements[ct] /= fLength; m_tElements[ct] /= fLength;
//This shouldn't happen as we had the length check earlier. So it's probably a bug if it does happen.
POLYVOX_ASSERT(m_tElements[ct] == m_tElements[ct], "Obtained NAN during vector normalisation. Perhaps the input vector was too short?"); POLYVOX_ASSERT(m_tElements[ct] == m_tElements[ct], "Obtained NAN during vector normalisation. Perhaps the input vector was too short?");
} }
} }

View File

@ -30,10 +30,6 @@ namespace PolyVox
//If this is not the case then the output is undefined. //If this is not the case then the output is undefined.
uint8_t logBase2(uint32_t uInput) uint8_t logBase2(uint32_t uInput)
{ {
//Debug mode validation
POLYVOX_ASSERT(uInput != 0, "Cannot compute the log of zero.");
POLYVOX_ASSERT(isPowerOf2(uInput), "Input must be a power of two in order to compute the log.");
//Release mode validation //Release mode validation
if(uInput == 0) if(uInput == 0)
{ {

View File

@ -78,7 +78,10 @@ namespace PolyVox
*/ */
void Region::accumulate(const Region& reg) void Region::accumulate(const Region& reg)
{ {
POLYVOX_ASSERT(reg.isValid(), "You cannot accumulate an invalid region."); //The result of accumulating an invalid region is not defined. if(!reg.isValid())
{
POLYVOX_THROW(invalid_operation, "You cannot accumulate an invalid region."); //The result of accumulating an invalid region is not defined.
}
m_iLowerX = ((std::min)(m_iLowerX, reg.getLowerX())); m_iLowerX = ((std::min)(m_iLowerX, reg.getLowerX()));
m_iLowerY = ((std::min)(m_iLowerY, reg.getLowerY())); m_iLowerY = ((std::min)(m_iLowerY, reg.getLowerY()));