Newer
Older
/***************************************************************************
Array_impl.h - description
-------------------
begin : Nov 8, 2012
copyright : (C) 2012 by Tomas Oberhuber
email : tomas.oberhuber@fjfi.cvut.cz
***************************************************************************/
/* See Copyright Notice in tnl/Copyright */
#include <TNL/Assert.h>
#include <TNL/File.h>
#include <TNL/Math.h>
#include <TNL/param-types.h>
Jakub Klinkovský
committed
#include <TNL/Containers/Algorithms/ArrayOperations.h>
#include <TNL/Containers/Algorithms/ArrayIO.h>
template< typename Value,
typename Device,
typename Index >
Array< Value, Device, Index >::
: size( 0 ),
data( 0 ),
allocationPointer( 0 ),
referenceCounter( 0 )
template< typename Value,
typename Device,
typename Index >
Array< Value, Device, Index >::
Array( const IndexType& size )
: size( 0 ),
data( 0 ),
allocationPointer( 0 ),
referenceCounter( 0 )
{
this->setSize( size );
}
template< typename Value,
typename Device,
typename Index >
Array< Value, Device, Index >::
Array( Value* data,
: size( size ),
data( data ),
allocationPointer( 0 ),
referenceCounter( 0 )
template< typename Value,
typename Device,
typename Index >
Array< Value, Device, Index >::
Array( Array< Value, Device, Index >& array,
const IndexType& begin,
const IndexType& size )
: size( size ),
data( &array.getData()[ begin ] ),
allocationPointer( array.allocationPointer ),
referenceCounter( 0 )
{
TNL_ASSERT_TRUE( array.getData(), "Empty arrays cannot be bound." );
TNL_ASSERT_LT( begin, array.getSize(), "Begin of array is out of bounds." );
TNL_ASSERT_LE( begin + size, array.getSize(), "End of array is out of bounds." );
if( ! this->size )
this->size = array.getSize() - begin;
if( array.allocationPointer )
{
if( array.referenceCounter )
{
this->referenceCounter = array.referenceCounter;
this->referenceCounter = array.referenceCounter = new int( 2 );
template< typename Value,
typename Device,
typename Index >
Array< Value, Device, Index >::
return String( "Containers::Array< " ) +
TNL::getType< Value >() + ", " +
Device::getDeviceType() + ", " +
TNL::getType< Index >() + " >";
template< typename Value,
typename Device,
typename Index >
Array< Value, Device, Index >::
{
return this->getType();
template< typename Value,
typename Device,
typename Index >
Array< Value, Device, Index >::
{
return HostType::getType();
template< typename Value,
typename Device,
typename Index >
Array< Value, Device, Index >::
getSerializationTypeVirtual() const
{
return this->getSerializationType();
template< typename Value,
typename Device,
typename Index >
Array< Value, Device, Index >::
releaseData() const
{
if( this->referenceCounter )
{
if( --*this->referenceCounter == 0 )
{
Jakub Klinkovský
committed
Algorithms::ArrayOperations< Device >::freeMemory( this->allocationPointer );
delete this->referenceCounter;
//std::cerr << "Deallocating reference counter " << this->referenceCounter << std::endl;
Jakub Klinkovský
committed
Algorithms::ArrayOperations< Device >::freeMemory( this->allocationPointer );
this->allocationPointer = 0;
this->data = 0;
this->size = 0;
this->referenceCounter = 0;
}
template< typename Value,
typename Device,
typename Index >
Jakub Klinkovský
committed
void
Array< Value, Device, Index >::
TNL_ASSERT_GE( size, 0, "Array size must be non-negative." );
Jakub Klinkovský
committed
if( this->size == size && allocationPointer && ! referenceCounter )
return;
// Allocating zero bytes is useless. Moreover, the allocators don't behave the same way:
// "operator new" returns some non-zero address, the latter returns a null pointer.
if( size > 0 ) {
Algorithms::ArrayOperations< Device >::allocateMemory( this->allocationPointer, size );
this->data = this->allocationPointer;
this->size = size;
TNL_ASSERT_TRUE( this->allocationPointer,
"This should never happen - allocator did not throw on an error." );
Jakub Klinkovský
committed
}
template< typename Value,
typename Device,
typename Index >
__cuda_callable__
Index
Array< Value, Device, Index >::
getSize() const
{
return this -> size;
}
template< typename Value,
typename Device,
typename Index >
template< typename ArrayT >
Jakub Klinkovský
committed
void
Array< Value, Device, Index >::
setLike( const ArrayT& array )
Jakub Klinkovský
committed
setSize( array.getSize() );
}
template< typename Value,
typename Device,
typename Index >
Array< Value, Device, Index >::
bind( Value* data,
TNL_ASSERT_TRUE( data, "Null pointer cannot be bound." );
this->releaseData();
this->data = data;
template< typename Value,
typename Device,
typename Index >
template< typename ArrayT >
Array< Value, Device, Index >::
bind( const ArrayT& array,
const IndexType& begin,
const IndexType& size )
{
// all template parameters of Array must match, otherwise binding does not make sense
static_assert( std::is_same< Value, typename ArrayT::ValueType >::value, "ValueType of both arrays must be the same." );
static_assert( std::is_same< Device, typename ArrayT::DeviceType >::value, "DeviceType of both arrays must be the same." );
static_assert( std::is_same< Index, typename ArrayT::IndexType >::value, "IndexType of both arrays must be the same." );
TNL_ASSERT_TRUE( array.getData(), "Empty array cannot be bound." );
TNL_ASSERT_LT( begin, array.getSize(), "Begin of array is out of bounds." );
TNL_ASSERT_LE( begin + size, array.getSize(), "End of array is out of bounds." );
this->releaseData();
if( size )
this->size = size;
else
this->size = array.getSize() - begin;
this->data = const_cast< Value* >( &array.getData()[ begin ] );
this->allocationPointer = array.allocationPointer;
if( array.allocationPointer )
{
if( array.referenceCounter )
{
this->referenceCounter = array.referenceCounter;
this->referenceCounter = array.referenceCounter = new int( 2 );
//std::cerr << "Allocating reference counter " << this->referenceCounter << std::endl;
template< typename Value,
typename Device,
typename Index >
template< int Size >
void
Array< Value, Device, Index >::
bind( StaticArray< Size, Value >& array )
{
this->releaseData();
this->size = Size;
this->data = array.getData();
}
template< typename Value,
typename Device,
typename Index >
Array< Value, Device, Index >::
swap( Array< Value, Device, Index >& array )
TNL::swap( this->size, array.size );
TNL::swap( this->data, array.data );
TNL::swap( this->allocationPointer, array.allocationPointer );
TNL::swap( this->referenceCounter, array.referenceCounter );
Jakub Klinkovský
committed
}
template< typename Value,
typename Device,
typename Index >
Array< Value, Device, Index >::
Jakub Klinkovský
committed
}
template< typename Value,
typename Device,
typename Index >
__cuda_callable__
const Value* Array< Value, Device, Index >::getData() const
return this->data;
Jakub Klinkovský
committed
}
template< typename Value,
typename Device,
typename Index >
__cuda_callable__
Value* Array< Value, Device, Index >::getData()
return this->data;
Jakub Klinkovský
committed
}
template< typename Value,
Tomáš Oberhuber
committed
typename Device,
typename Index >
Array< Value, Device, Index >::
setElement( const Index& i, const Value& x )
Tomáš Oberhuber
committed
{
TNL_ASSERT_GE( i, 0, "Element index must be non-negative." );
TNL_ASSERT_LT( i, this->getSize(), "Element index is out of bounds." );
return Algorithms::ArrayOperations< Device >::setMemoryElement( &( this->data[ i ] ), x );
template< typename Value,
typename Device,
typename Index >
Array< Value, Device, Index >::
getElement( const Index& i ) const
TNL_ASSERT_GE( i, 0, "Element index must be non-negative." );
TNL_ASSERT_LT( i, this->getSize(), "Element index is out of bounds." );
return Algorithms::ArrayOperations< Device >::getMemoryElement( & ( this->data[ i ] ) );
Tomáš Oberhuber
committed
}
template< typename Value,
typename Device,
typename Index >
inline Value&
Array< Value, Device, Index >::
operator[] ( const Index& i )
TNL_ASSERT_GE( i, 0, "Element index must be non-negative." );
TNL_ASSERT_LT( i, this->getSize(), "Element index is out of bounds." );
return this->data[ i ];
Jakub Klinkovský
committed
}
template< typename Value,
typename Device,
typename Index >
inline const Value&
Array< Value, Device, Index >::
operator[] ( const Index& i ) const
TNL_ASSERT_GE( i, 0, "Element index must be non-negative." );
TNL_ASSERT_LT( i, this->getSize(), "Element index is out of bounds." );
return this->data[ i ];
Jakub Klinkovský
committed
}
template< typename Value,
typename Device,
typename Index >
Array< Value, Device, Index >&
Array< Value, Device, Index >::
operator = ( const Array< Value, Device, Index >& array )
//TNL_ASSERT_EQ( array.getSize(), this->getSize(), "Array sizes must be the same." );
if( this->getSize() != array.getSize() )
this->setLike( array );
if( this->getSize() > 0 )
Algorithms::ArrayOperations< Device >::
copyMemory( this->getData(),
array.getData(),
array.getSize() );
Jakub Klinkovský
committed
}
template< typename Value,
typename Device,
typename Index >
template< typename ArrayT >
Array< Value, Device, Index >&
Array< Value, Device, Index >::
operator = ( const ArrayT& array )
//TNL_ASSERT_EQ( array.getSize(), this->getSize(), "Array sizes must be the same." );
if( this->getSize() != array.getSize() )
this->setLike( array );
if( this->getSize() > 0 )
Algorithms::ArrayOperations< Device, typename ArrayT::DeviceType >::
copyMemory( this->getData(),
array.getData(),
array.getSize() );
Jakub Klinkovský
committed
}
template< typename Value,
typename Device,
typename Index >
template< typename ArrayT >
Array< Value, Device, Index >::
operator == ( const ArrayT& array ) const
if( this->getSize() == 0 )
return true;
Jakub Klinkovský
committed
return Algorithms::ArrayOperations< Device, typename ArrayT::DeviceType >::
compareMemory( this->getData(),
array.getData(),
array.getSize() );
template< typename Value,
typename Device,
typename Index >
template< typename ArrayT >
bool Array< Value, Device, Index >::operator != ( const ArrayT& array ) const
{
return ! ( ( *this ) == array );
}
template< typename Value,
void Array< Value, Device, Index >::setValue( const Value& e )
TNL_ASSERT_TRUE( this->getData(), "Attempted to set a value of an empty array." );
Jakub Klinkovský
committed
Algorithms::ArrayOperations< Device >::setMemory( this->getData(), e, this->getSize() );
template< typename Value,
typename Device,
typename Index >
bool
Array< Value, Device, Index >::
containsValue( const Value& v ) const
return Algorithms::ArrayOperations< Device >::containsValue( this->data, this->size, v );
template< typename Value,
typename Device,
typename Index >
bool
Array< Value, Device, Index >::
containsOnlyValue( const Value& v ) const
return Algorithms::ArrayOperations< Device >::containsOnlyValue( this->data, this->size, v );
template< typename Value,
typename Device,
typename Index >
Array< Value, Device, Index >::operator bool() const
{
return data != 0;
Jakub Klinkovský
committed
}
template< typename Value,
typename Device,
typename Index >
bool Array< Value, Device, Index >::save( File& file ) const
if( ! Object::save( file ) )
if( ! file.write( &this->size ) )
if( this->size != 0 && ! Algorithms::ArrayIO< Value, Device, Index >::save( file, this->data, this->size ) )
std::cerr << "I was not able to save " << this->getType()
<< " with size " << this -> getSize() << std::endl;
return false;
}
return true;
Jakub Klinkovský
committed
}
template< typename Value,
typename Device,
typename Index >
Array< Value, Device, Index >::
if( ! Object::load( file ) )
if( ! file.read( &_size ) )
{
std::cerr << "Unable to read the array size." << std::endl;
std::cerr << "Error: The size " << _size << " of the file is not a positive number or zero." << std::endl;
if( ! Algorithms::ArrayIO< Value, Device, Index >::load( file, this->data, this->size ) )
std::cerr << "I was not able to load " << this->getType()
<< " with size " << this -> getSize() << std::endl;
}
return true;
}
template< typename Value,
typename Device,
typename Index >
bool
Array< Value, Device, Index >::
boundLoad( File& file )
if( ! Object::load( file ) )
return false;
Index _size;
if( ! file.read( &_size ) )
return false;
if( _size < 0 )
{
std::cerr << "Error: The size " << _size << " of the file is not a positive number or zero." << std::endl;
return false;
}
if( this->getSize() != 0 )
{
if( this->getSize() != _size )
{
std::cerr << "Error: The current array size is not zero (" << this->getSize() << ") and it is different from the size of "
<< "the array being loaded (" << _size << "). This is not possible. Call method reset() before." << std::endl;
return false;
}
}
else setSize( _size );
if( _size )
{
if( ! Algorithms::ArrayIO< Value, Device, Index >::load( file, this->data, this->size ) )
std::cerr << "I was not able to load " << this->getType()
<< " with size " << this -> getSize() << std::endl;
return false;
}
}
return true;
}

Vít Hanousek
committed
template< typename Value,
Array< Value, Device, Index >::
template< typename Value, typename Device, typename Index >
std::ostream& operator << ( std::ostream& str, const Array< Value, Device, Index >& v )
str << "[ ";
if( v.getSize() > 0 )
{
str << v.getElement( 0 );
for( Index i = 1; i < v.getSize(); i++ )
str << ", " << v.getElement( i );