Skip to content
Snippets Groups Projects
Commit 44c2437f authored by Sebastian Eibl's avatar Sebastian Eibl
Browse files

[API] made SendBuffer memory access more high level

parent 57db1671
Branches
Tags
No related merge requests found
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <boost/mpl/logical.hpp> #include <boost/mpl/logical.hpp>
#include <boost/type_traits/is_enum.hpp> #include <boost/type_traits/is_enum.hpp>
#include <boost/type_traits/is_arithmetic.hpp> #include <boost/type_traits/is_arithmetic.hpp>
#include <boost/type_traits/is_fundamental.hpp>
#include <boost/utility/enable_if.hpp> #include <boost/utility/enable_if.hpp>
#include <algorithm> #include <algorithm>
...@@ -80,10 +81,30 @@ namespace mpi { ...@@ -80,10 +81,30 @@ namespace mpi {
// also the RecvBuffer class description for the receiver side of the MPI communication. // also the RecvBuffer class description for the receiver side of the MPI communication.
*/ */
template< typename T = unsigned char // Element type template< typename T = unsigned char // Element type
, typename G = OptimalGrowth > // Growth policy , typename G = OptimalGrowth > // Growth policy
class GenericSendBuffer class GenericSendBuffer
{ {
public: public:
template <typename VT>
class Ptr
{
public:
static_assert( boost::is_fundamental<VT>::value, "only fundamental data types are allowed");
typedef VT value_type;
Ptr(GenericSendBuffer<T, G>& buffer, const std::ptrdiff_t offset, const size_t length)
: buffer_(buffer), offset_(offset), length_(length) {}
inline VT& operator*();
inline VT* operator->();
inline VT& operator[](const size_t& rhs);
private:
GenericSendBuffer<T, G>& buffer_;
const std::ptrdiff_t offset_;
const size_t length_;
};
//**Type definitions************************************************************************************************* //**Type definitions*************************************************************************************************
typedef T ElementType; //!< Type of the receive buffer elements. typedef T ElementType; //!< Type of the receive buffer elements.
//******************************************************************************************************************* //*******************************************************************************************************************
...@@ -92,7 +113,7 @@ public: ...@@ -92,7 +113,7 @@ public:
/*!\name Constructors */ /*!\name Constructors */
//@{ //@{
explicit inline GenericSendBuffer( size_t initCapacity = 0 ); explicit inline GenericSendBuffer( size_t initCapacity = 0 );
inline GenericSendBuffer( const GenericSendBuffer& sb ); inline GenericSendBuffer( const GenericSendBuffer& sb );
//@} //@}
//******************************************************************************************************************* //*******************************************************************************************************************
...@@ -125,7 +146,7 @@ public: ...@@ -125,7 +146,7 @@ public:
//@{ //@{
template< typename V > template< typename V >
typename boost::enable_if< boost::mpl::or_< boost::is_arithmetic<V>, boost::is_enum<V> >, typename boost::enable_if< boost::mpl::or_< boost::is_arithmetic<V>, boost::is_enum<V> >,
GenericSendBuffer& >::type GenericSendBuffer& >::type
operator<<( V value ); operator<<( V value );
//@} //@}
...@@ -140,9 +161,23 @@ public: ...@@ -140,9 +161,23 @@ public:
//**Utility functions************************************************************************************************ //**Utility functions************************************************************************************************
/*!\name Utility functions */ /*!\name Utility functions */
//@{ //@{
/**
* Returns a special pointer class to modify the allocated memory location later.
*
* Example:
* \snippet BufferTest.cpp SendBuffer Overwrite Test
* The buffer now contains 1, 3, 2, 3
*/
template <typename VT>
inline
Ptr<VT> allocate( const size_t length = 1, const VT& v = VT() )
{
auto tmp = typename GenericSendBuffer<T,G>::template Ptr<VT>(*this, getOffset(), length);
for (size_t i = 0; i < length; ++i)
*this << v;
return tmp;
}
inline T* ptr () const; inline T* ptr () const;
inline std::ptrdiff_t getOffset() const;
inline T* getMemoryLocation( const std::ptrdiff_t offset);
inline void reserve( size_t newCapacity ); inline void reserve( size_t newCapacity );
inline void clear (); inline void clear ();
inline void reset (); inline void reset ();
...@@ -158,8 +193,11 @@ private: ...@@ -158,8 +193,11 @@ private:
template< typename V > template< typename V >
typename boost::enable_if< boost::mpl::or_< boost::is_arithmetic<V>, boost::is_enum<V> >, typename boost::enable_if< boost::mpl::or_< boost::is_arithmetic<V>, boost::is_enum<V> >,
GenericSendBuffer& >::type GenericSendBuffer& >::type
put( V value ); put( V value );
inline std::ptrdiff_t getOffset() const;
inline T* getMemoryLocation( const std::ptrdiff_t offset);
//@} //@}
//******************************************************************************************************************* //*******************************************************************************************************************
...@@ -184,6 +222,45 @@ private: ...@@ -184,6 +222,45 @@ private:
typedef GenericSendBuffer<> SendBuffer; typedef GenericSendBuffer<> SendBuffer;
//======================================================================================================================
//
// GenericSendBuffer<T,G>::Ptr<VT>
//
//======================================================================================================================
template< typename T // Element type
, typename G > // Growth policy
template <typename VT>
inline
VT& GenericSendBuffer<T,G>::Ptr<VT>::operator*()
{
return *operator->();
}
template< typename T // Element type
, typename G > // Growth policy
template <typename VT>
inline
VT* GenericSendBuffer<T,G>::Ptr<VT>::operator->()
{
return reinterpret_cast<value_type*>( buffer_.getMemoryLocation( offset_ + static_cast<std::ptrdiff_t>(BUFFER_DEBUG_OVERHEAD) ) );
}
template< typename T // Element type
, typename G > // Growth policy
template <typename VT>
inline
VT& GenericSendBuffer<T,G>::Ptr<VT>::operator[](const size_t& rhs)
{
WALBERLA_ASSERT_LESS(rhs, length_, "out of bounds access!");
return *reinterpret_cast<value_type*>(
buffer_.getMemoryLocation(
offset_ +
static_cast<std::ptrdiff_t>( rhs * ( BUFFER_DEBUG_OVERHEAD + sizeof(VT) ) )
)
);
}
//====================================================================================================================== //======================================================================================================================
// //
...@@ -199,7 +276,7 @@ typedef GenericSendBuffer<> SendBuffer; ...@@ -199,7 +276,7 @@ typedef GenericSendBuffer<> SendBuffer;
// The default initial capacity of the send buffer is specified by the selected growth policy. // The default initial capacity of the send buffer is specified by the selected growth policy.
*/ */
template< typename T // Element type template< typename T // Element type
, typename G > // Growth policy , typename G > // Growth policy
inline GenericSendBuffer<T,G>::GenericSendBuffer( size_t initCapacity ) inline GenericSendBuffer<T,G>::GenericSendBuffer( size_t initCapacity )
: begin_( new T[initCapacity] ) // Pointer to the first element : begin_( new T[initCapacity] ) // Pointer to the first element
, cur_ ( begin_ ) // Pointer to the current/last element , cur_ ( begin_ ) // Pointer to the current/last element
...@@ -214,7 +291,7 @@ inline GenericSendBuffer<T,G>::GenericSendBuffer( size_t initCapacity ) ...@@ -214,7 +291,7 @@ inline GenericSendBuffer<T,G>::GenericSendBuffer( size_t initCapacity )
// \param sb The send buffer to be copied. // \param sb The send buffer to be copied.
*/ */
template< typename T // Element type template< typename T // Element type
, typename G > // Growth policy , typename G > // Growth policy
inline GenericSendBuffer<T,G>::GenericSendBuffer( const GenericSendBuffer& sb ) inline GenericSendBuffer<T,G>::GenericSendBuffer( const GenericSendBuffer& sb )
: begin_( new T[sb.size()] ) // Pointer to the first element : begin_( new T[sb.size()] ) // Pointer to the first element
, cur_ ( begin_+sb.size() ) // Pointer to the current/last element , cur_ ( begin_+sb.size() ) // Pointer to the current/last element
...@@ -238,7 +315,7 @@ inline GenericSendBuffer<T,G>::GenericSendBuffer( const GenericSendBuffer& sb ) ...@@ -238,7 +315,7 @@ inline GenericSendBuffer<T,G>::GenericSendBuffer( const GenericSendBuffer& sb )
/*!\brief Destructor for SendBuffer. /*!\brief Destructor for SendBuffer.
*/ */
template< typename T // Element type template< typename T // Element type
, typename G > // Growth policy , typename G > // Growth policy
inline GenericSendBuffer<T,G>::~GenericSendBuffer() inline GenericSendBuffer<T,G>::~GenericSendBuffer()
{ {
delete [] begin_; delete [] begin_;
...@@ -261,7 +338,7 @@ inline GenericSendBuffer<T,G>::~GenericSendBuffer() ...@@ -261,7 +338,7 @@ inline GenericSendBuffer<T,G>::~GenericSendBuffer()
// \return Reference to the assigned send buffer. // \return Reference to the assigned send buffer.
*/ */
template< typename T // Element type template< typename T // Element type
, typename G > // Growth policy , typename G > // Growth policy
GenericSendBuffer<T,G>& GenericSendBuffer<T,G>::operator=( const GenericSendBuffer& sb ) GenericSendBuffer<T,G>& GenericSendBuffer<T,G>::operator=( const GenericSendBuffer& sb )
{ {
if( &sb == this ) return *this; if( &sb == this ) return *this;
...@@ -297,7 +374,7 @@ GenericSendBuffer<T,G>& GenericSendBuffer<T,G>::operator=( const GenericSendBuff ...@@ -297,7 +374,7 @@ GenericSendBuffer<T,G>& GenericSendBuffer<T,G>::operator=( const GenericSendBuff
// \return The maximum possible size. // \return The maximum possible size.
*/ */
template< typename T // Element type template< typename T // Element type
, typename G > // Growth policy , typename G > // Growth policy
inline size_t GenericSendBuffer<T,G>::maxSize() const inline size_t GenericSendBuffer<T,G>::maxSize() const
{ {
return size_t(-1) / sizeof(T); return size_t(-1) / sizeof(T);
...@@ -311,7 +388,7 @@ inline size_t GenericSendBuffer<T,G>::maxSize() const ...@@ -311,7 +388,7 @@ inline size_t GenericSendBuffer<T,G>::maxSize() const
// \return The current size. // \return The current size.
*/ */
template< typename T // Element type template< typename T // Element type
, typename G > // Growth policy , typename G > // Growth policy
inline size_t GenericSendBuffer<T,G>::size() const inline size_t GenericSendBuffer<T,G>::size() const
{ {
return numeric_cast< size_t >( cur_ - begin_ ); return numeric_cast< size_t >( cur_ - begin_ );
...@@ -325,7 +402,7 @@ inline size_t GenericSendBuffer<T,G>::size() const ...@@ -325,7 +402,7 @@ inline size_t GenericSendBuffer<T,G>::size() const
// \return The capacity. // \return The capacity.
*/ */
template< typename T // Element type template< typename T // Element type
, typename G > // Growth policy , typename G > // Growth policy
inline size_t GenericSendBuffer<T,G>::capacity() const inline size_t GenericSendBuffer<T,G>::capacity() const
{ {
return numeric_cast< size_t >( end_ - begin_ ); return numeric_cast< size_t >( end_ - begin_ );
...@@ -339,7 +416,7 @@ inline size_t GenericSendBuffer<T,G>::capacity() const ...@@ -339,7 +416,7 @@ inline size_t GenericSendBuffer<T,G>::capacity() const
// \return \a true if the send buffer is empty, \a false if it is not. // \return \a true if the send buffer is empty, \a false if it is not.
*/ */
template< typename T // Element type template< typename T // Element type
, typename G > // Growth policy , typename G > // Growth policy
inline bool GenericSendBuffer<T,G>::isEmpty() const inline bool GenericSendBuffer<T,G>::isEmpty() const
{ {
return begin_ == cur_; return begin_ == cur_;
...@@ -362,15 +439,15 @@ inline bool GenericSendBuffer<T,G>::isEmpty() const ...@@ -362,15 +439,15 @@ inline bool GenericSendBuffer<T,G>::isEmpty() const
// //
*/ */
template< typename T // Element type template< typename T // Element type
, typename G > // Growth policy , typename G > // Growth policy
template< typename V > // Type of the built-in data value template< typename V > // Type of the built-in data value
typename boost::enable_if< boost::mpl::or_< boost::is_arithmetic<V>, boost::is_enum<V> >, typename boost::enable_if< boost::mpl::or_< boost::is_arithmetic<V>, boost::is_enum<V> >,
GenericSendBuffer<T,G>& >::type GenericSendBuffer<T,G>& >::type
GenericSendBuffer<T,G>::put( V value ) GenericSendBuffer<T,G>::put( V value )
{ {
// Compile time check that V is built-in data type // Compile time check that V is built-in data type
static_assert( boost::is_arithmetic<V>::value || boost::is_enum<V>::value, static_assert( boost::is_arithmetic<V>::value || boost::is_enum<V>::value,
"SendBuffer accepts only built-in data types"); "SendBuffer accepts only built-in data types");
static_assert( sizeof(V) >= sizeof(T), "Type that is stored has to be bigger than T" ); static_assert( sizeof(V) >= sizeof(T), "Type that is stored has to be bigger than T" );
static_assert( sizeof(V) % sizeof(T) == 0, "V has to be divisible by T "); static_assert( sizeof(V) % sizeof(T) == 0, "V has to be divisible by T ");
...@@ -408,10 +485,10 @@ GenericSendBuffer<T,G>::put( V value ) ...@@ -408,10 +485,10 @@ GenericSendBuffer<T,G>::put( V value )
// a user-defined data type results in a compile time error! // a user-defined data type results in a compile time error!
*/ */
template< typename T // Element type template< typename T // Element type
, typename G > // Growth policy , typename G > // Growth policy
template< typename V > // Type of the built-in data value template< typename V > // Type of the built-in data value
typename boost::enable_if< boost::mpl::or_< boost::is_arithmetic<V>, boost::is_enum<V> >, typename boost::enable_if< boost::mpl::or_< boost::is_arithmetic<V>, boost::is_enum<V> >,
GenericSendBuffer<T,G>& >::type GenericSendBuffer<T,G>& >::type
GenericSendBuffer<T,G>::operator<<( V value ) GenericSendBuffer<T,G>::operator<<( V value )
{ {
addDebugMarker( typeid(V).name() ); addDebugMarker( typeid(V).name() );
...@@ -448,7 +525,7 @@ GenericSendBuffer<T,G>::operator<<( V value ) ...@@ -448,7 +525,7 @@ GenericSendBuffer<T,G>::operator<<( V value )
\endcode \endcode
*/ */
template< typename T // Element type template< typename T // Element type
, typename G > // Growth policy , typename G > // Growth policy
inline void GenericSendBuffer<T,G>::rewind(const size_t & s) inline void GenericSendBuffer<T,G>::rewind(const size_t & s)
{ {
WALBERLA_ASSERT_LESS(s, size()); WALBERLA_ASSERT_LESS(s, size());
...@@ -463,6 +540,7 @@ inline void GenericSendBuffer<T,G>::rewind(const size_t & s) ...@@ -463,6 +540,7 @@ inline void GenericSendBuffer<T,G>::rewind(const size_t & s)
// //
//====================================================================================================================== //======================================================================================================================
//********************************************************************************************************************** //**********************************************************************************************************************
/*!\brief Returns a pointer to the first element of the send buffer. /*!\brief Returns a pointer to the first element of the send buffer.
// //
...@@ -485,7 +563,7 @@ inline void GenericSendBuffer<T,G>::rewind(const size_t & s) ...@@ -485,7 +563,7 @@ inline void GenericSendBuffer<T,G>::rewind(const size_t & s)
\endcode \endcode
*/ */
template< typename T // Element type template< typename T // Element type
, typename G > // Growth policy , typename G > // Growth policy
inline T* GenericSendBuffer<T,G>::ptr() const inline T* GenericSendBuffer<T,G>::ptr() const
{ {
return begin_; return begin_;
...@@ -495,14 +573,11 @@ inline T* GenericSendBuffer<T,G>::ptr() const ...@@ -495,14 +573,11 @@ inline T* GenericSendBuffer<T,G>::ptr() const
/** /**
* Returns the offset from the beginning to the current position inside the buffer in bytes. * Returns the offset from the beginning to the current position inside the buffer in bytes.
* *
* Example:
* \snippet BufferTest.cpp SendBuffer Overwrite Test
* The buffer now contains 3, 2, 3
* \attention This is a low level function. Use with care! * \attention This is a low level function. Use with care!
* \see getMemoryLocation() * \see getMemoryLocation()
*/ */
template< typename T // Element type template< typename T // Element type
, typename G > // Growth policy , typename G > // Growth policy
inline std::ptrdiff_t GenericSendBuffer<T,G>::getOffset() const inline std::ptrdiff_t GenericSendBuffer<T,G>::getOffset() const
{ {
return cur_ - begin_; return cur_ - begin_;
...@@ -512,14 +587,11 @@ inline std::ptrdiff_t GenericSendBuffer<T,G>::getOffset() const ...@@ -512,14 +587,11 @@ inline std::ptrdiff_t GenericSendBuffer<T,G>::getOffset() const
/** /**
* Returns the memory address corresponding to the offset. Offset is measured in bytes from the beginning of the buffer. * Returns the memory address corresponding to the offset. Offset is measured in bytes from the beginning of the buffer.
* *
* Example:
* \snippet BufferTest.cpp SendBuffer Overwrite Test
* The buffer now contains 3, 2, 3
* \attention This is a low level function. Use with care! * \attention This is a low level function. Use with care!
* \see getOffset() * \see getOffset()
*/ */
template< typename T // Element type template< typename T // Element type
, typename G > // Growth policy , typename G > // Growth policy
inline T* GenericSendBuffer<T,G>::getMemoryLocation( const std::ptrdiff_t offset) inline T* GenericSendBuffer<T,G>::getMemoryLocation( const std::ptrdiff_t offset)
{ {
return begin_ + offset; return begin_ + offset;
...@@ -536,7 +608,7 @@ inline T* GenericSendBuffer<T,G>::getMemoryLocation( const std::ptrdiff_t offs ...@@ -536,7 +608,7 @@ inline T* GenericSendBuffer<T,G>::getMemoryLocation( const std::ptrdiff_t offs
// buffer. // buffer.
*/ */
template< typename T // Element type template< typename T // Element type
, typename G > // Growth policy , typename G > // Growth policy
inline void GenericSendBuffer<T,G>::reserve( size_t newCapacity ) inline void GenericSendBuffer<T,G>::reserve( size_t newCapacity )
{ {
if( newCapacity > capacity() ) if( newCapacity > capacity() )
...@@ -552,7 +624,7 @@ inline void GenericSendBuffer<T,G>::reserve( size_t newCapacity ) ...@@ -552,7 +624,7 @@ inline void GenericSendBuffer<T,G>::reserve( size_t newCapacity )
// \return void // \return void
*/ */
template< typename T // Element type template< typename T // Element type
, typename G > // Growth policy , typename G > // Growth policy
void GenericSendBuffer<T,G>::extendMemory( size_t newCapacity ) void GenericSendBuffer<T,G>::extendMemory( size_t newCapacity )
{ {
// Calculating the new capacity // Calculating the new capacity
...@@ -580,7 +652,7 @@ void GenericSendBuffer<T,G>::extendMemory( size_t newCapacity ) ...@@ -580,7 +652,7 @@ void GenericSendBuffer<T,G>::extendMemory( size_t newCapacity )
// This function performs a complete reset of the send buffer. // This function performs a complete reset of the send buffer.
*/ */
template< typename T // Element type template< typename T // Element type
, typename G > // Growth policy , typename G > // Growth policy
inline void GenericSendBuffer<T,G>::clear() inline void GenericSendBuffer<T,G>::clear()
{ {
cur_ = begin_; cur_ = begin_;
...@@ -596,7 +668,7 @@ inline void GenericSendBuffer<T,G>::clear() ...@@ -596,7 +668,7 @@ inline void GenericSendBuffer<T,G>::clear()
// This function performs a complete reset of the send buffer - including the deletion of allocated memory! // This function performs a complete reset of the send buffer - including the deletion of allocated memory!
*/ */
template< typename T // Element type template< typename T // Element type
, typename G > // Growth policy , typename G > // Growth policy
inline void GenericSendBuffer<T,G>::reset() inline void GenericSendBuffer<T,G>::reset()
{ {
delete [] begin_; delete [] begin_;
...@@ -615,7 +687,7 @@ inline void GenericSendBuffer<T,G>::reset() ...@@ -615,7 +687,7 @@ inline void GenericSendBuffer<T,G>::reset()
#ifdef WALBERLA_BUFFER_DEBUG #ifdef WALBERLA_BUFFER_DEBUG
template< typename T // Element type template< typename T // Element type
, typename G > // Growth policy , typename G > // Growth policy
inline void GenericSendBuffer<T,G>::addDebugMarker( const char * marker ) inline void GenericSendBuffer<T,G>::addDebugMarker( const char * marker )
{ {
uint_t len = std::strlen( marker ); uint_t len = std::strlen( marker );
...@@ -629,7 +701,7 @@ inline void GenericSendBuffer<T,G>::addDebugMarker( const char * marker ) ...@@ -629,7 +701,7 @@ inline void GenericSendBuffer<T,G>::addDebugMarker( const char * marker )
} }
#else #else
template< typename T // Element type template< typename T // Element type
, typename G > // Growth policy , typename G > // Growth policy
inline void GenericSendBuffer<T,G>::addDebugMarker( const char * ) inline void GenericSendBuffer<T,G>::addDebugMarker( const char * )
{} {}
#endif #endif
......
...@@ -306,9 +306,11 @@ void bufferOverwriteTest() ...@@ -306,9 +306,11 @@ void bufferOverwriteTest()
int b = 2; int b = 2;
int c = 3; int c = 3;
SendBuffer sb; SendBuffer sb;
auto offset = sb.getOffset(); auto ptr = sb.allocate<int>(2);
sb << a << b << c; sb << b << c;
*reinterpret_cast<int*>(sb.getMemoryLocation(offset)) = c; *ptr = a;
ptr[1] = c;
//ptr[2] = c; // will fail in debug: out of bounds
//! [SendBuffer Overwrite Test] //! [SendBuffer Overwrite Test]
// Copying // Copying
...@@ -316,6 +318,8 @@ void bufferOverwriteTest() ...@@ -316,6 +318,8 @@ void bufferOverwriteTest()
int recv; int recv;
rb >> recv;
WALBERLA_CHECK_EQUAL(a, recv);
rb >> recv; rb >> recv;
WALBERLA_CHECK_EQUAL(c, recv); WALBERLA_CHECK_EQUAL(c, recv);
rb >> recv; rb >> recv;
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment