diff --git a/src/Python/CMakeLists.txt b/src/Python/CMakeLists.txt index 82186a4ef123f7d3943a08f97fe7a8f565e312bf..43f58d0805d302d6af5f6c7c5ed0525d612ac529 100644 --- a/src/Python/CMakeLists.txt +++ b/src/Python/CMakeLists.txt @@ -1,3 +1,2 @@ INSTALL( FILES __init__.py - DESTINATION lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/TNL - PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) + DESTINATION lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/site-packages/TNL ) diff --git a/src/TNL/Containers/StaticVector.h b/src/TNL/Containers/StaticVector.h index 095c9c1ffefd2c9364562f6e9a0d65ee15c33387..ca410edfefaf94e4d74b3c84b91b72fad0c4d07d 100644 --- a/src/TNL/Containers/StaticVector.h +++ b/src/TNL/Containers/StaticVector.h @@ -24,8 +24,6 @@ class StaticVector : public StaticArray< Size, Real > typedef StaticVector< Size, Real > ThisType; enum { size = Size }; - using StaticArray< Size, Real >::operator=; - __cuda_callable__ StaticVector(); @@ -97,6 +95,23 @@ class StaticVector : public StaticArray< Size, Real > __cuda_callable__ Real lpNorm( const Real& p ) const; + +#ifdef HAVE_MIC + __cuda_callable__ + inline StaticVector< Size, Real >& operator=( const StaticVector< Size, Real >& vector ) + { + StaticArray< Size, Real >::operator=( vector ); + return *this; + } + + template< typename Vector > + __cuda_callable__ + inline StaticVector< Size, Real >& operator=( const Vector& vector ) + { + StaticArray< Size, Real >::operator=( vector ); + return *this; + } +#endif }; template< typename Real > @@ -107,8 +122,6 @@ class StaticVector< 1, Real > : public StaticArray< 1, Real > typedef StaticVector< 1, Real > ThisType; enum { size = 1 }; - using StaticArray< 1, Real >::operator=; - __cuda_callable__ StaticVector(); @@ -180,6 +193,23 @@ class StaticVector< 1, Real > : public StaticArray< 1, Real > __cuda_callable__ Real lpNorm( const Real& p ) const; + +#ifdef HAVE_MIC + __cuda_callable__ + inline StaticVector< 1, Real >& operator=( const StaticVector< 1, Real >& vector ) + { + StaticArray< 1, Real >::operator=( vector ); + return *this; + } + + template< typename Vector > + __cuda_callable__ + inline StaticVector< 1, Real >& operator=( const Vector& vector ) + { + StaticArray< 1, Real >::operator=( vector ); + return *this; + } +#endif }; template< typename Real > @@ -190,8 +220,6 @@ class StaticVector< 2, Real > : public StaticArray< 2, Real > typedef StaticVector< 2, Real > ThisType; enum { size = 2 }; - using StaticArray< 2, Real >::operator=; - __cuda_callable__ StaticVector(); @@ -266,6 +294,23 @@ class StaticVector< 2, Real > : public StaticArray< 2, Real > __cuda_callable__ Real lpNorm( const Real& p ) const; + +#ifdef HAVE_MIC + __cuda_callable__ + inline StaticVector< 2, Real >& operator=( const StaticVector< 2, Real >& vector ) + { + StaticArray< 2, Real >::operator=( vector ); + return *this; + } + + template< typename Vector > + __cuda_callable__ + inline StaticVector< 2, Real >& operator=( const Vector& vector ) + { + StaticArray< 2, Real >::operator=( vector ); + return *this; + } +#endif }; template< typename Real > @@ -276,8 +321,6 @@ class StaticVector< 3, Real > : public StaticArray< 3, Real > typedef StaticVector< 3, Real > ThisType; enum { size = 3 }; - using StaticArray< 3, Real >::operator=; - __cuda_callable__ StaticVector(); @@ -352,6 +395,23 @@ class StaticVector< 3, Real > : public StaticArray< 3, Real > __cuda_callable__ Real lpNorm( const Real& p ) const; + +#ifdef HAVE_MIC + __cuda_callable__ + inline StaticVector< 3, Real >& operator=( const StaticVector< 3, Real >& vector ) + { + StaticArray< 3, Real >::operator=( vector ); + return *this; + } + + template< typename Vector > + __cuda_callable__ + inline StaticVector< 3, Real >& operator=( const Vector& vector ) + { + StaticArray< 3, Real >::operator=( vector ); + return *this; + } +#endif }; template< int Size, typename Real, typename Scalar > diff --git a/src/TNL/Functions/Analytic/SinBumpsSDF_impl.h b/src/TNL/Functions/Analytic/SinBumpsSDF_impl.h index e72d92365c4c554a0803e79517da0b034428122b..4852a50358a615e02cd518a6ac0e71c4cc909657 100644 --- a/src/TNL/Functions/Analytic/SinBumpsSDF_impl.h +++ b/src/TNL/Functions/Analytic/SinBumpsSDF_impl.h @@ -86,7 +86,7 @@ getPartialDerivative( const PointType& v, const Real& time ) const { const RealType& x = v.x(); - RealType xp = ::fabs( x ) + sign( x ) * this->phase.x() * this->waveLength.x() / ( 2.0*M_PI ); + RealType xp = abs( x ) + sign( x ) * this->phase.x() * this->waveLength.x() / ( 2.0*M_PI ); if( this->wavesNumber.x() != 0.0 && xp > this->wavesNumber.x() * this->waveLength.x() ) return 0.0; if( YDiffOrder != 0 || ZDiffOrder != 0 ) @@ -239,4 +239,4 @@ getPartialDerivative( const PointType& v, } // namespace Analytic } // namespace Fucntions -} // namespace TNL \ No newline at end of file +} // namespace TNL diff --git a/src/TNL/Functions/Analytic/SinBumps_impl.h b/src/TNL/Functions/Analytic/SinBumps_impl.h index befe83856099c89a3cd87e972a375fbf3df4d124..44ea88c3c57d9512d8854f58520e892037eea127 100644 --- a/src/TNL/Functions/Analytic/SinBumps_impl.h +++ b/src/TNL/Functions/Analytic/SinBumps_impl.h @@ -101,7 +101,7 @@ getPartialDerivative( const PointType& v, return 0.0; const RealType& x = v.x(); - const RealType xp = ::fabs( x ) + sign( x ) * this->phase.x() * this->waveLength.x() / (2.0*M_PI); + const RealType xp = abs( x ) + sign( x ) * this->phase.x() * this->waveLength.x() / (2.0*M_PI); if( this->wavesNumber.x() != 0.0 && xp > this->waveLength.x() * this->wavesNumber.x() ) return 0.0; @@ -162,8 +162,8 @@ getPartialDerivative( const PointType& v, const RealType& x = v.x(); const RealType& y = v.y(); - const RealType xp = ::fabs( x ) + sign( x ) * this->phase.x() * this->waveLength.x() / (2.0*M_PI); - const RealType yp = ::fabs( y ) + sign( y ) * this->phase.y() * this->waveLength.y() / (2.0*M_PI); + const RealType xp = abs( x ) + sign( x ) * this->phase.x() * this->waveLength.x() / (2.0*M_PI); + const RealType yp = abs( y ) + sign( y ) * this->phase.y() * this->waveLength.y() / (2.0*M_PI); //std::cerr << "this->wavesNumber.x() = " << this->wavesNumber.x() << "fabs( x ) = " << fabs( x ) << " 2.0*M_PI * this->waveLength.x() * this->wavesNumber.x() = " << 2.0*M_PI * this->waveLength.x() * this->wavesNumber.x() << std::endl; if( ( this->wavesNumber.x() != 0.0 && xp > this->waveLength.x() * this->wavesNumber.x() ) || ( this->wavesNumber.y() != 0.0 && yp > this->waveLength.y() * this->wavesNumber.y() ) ) @@ -235,9 +235,9 @@ getPartialDerivative( const PointType& v, const RealType& y = v.y(); const RealType& z = v.z(); - const RealType xp = ::fabs( x ) + sign( x ) * this->phase.x() * this->waveLength.x() / (2.0*M_PI); - const RealType yp = ::fabs( y ) + sign( y ) * this->phase.y() * this->waveLength.y() / (2.0*M_PI); - const RealType zp = ::fabs( z ) + sign( z ) * this->phase.z() * this->waveLength.z() / (2.0*M_PI); + const RealType xp = abs( x ) + sign( x ) * this->phase.x() * this->waveLength.x() / (2.0*M_PI); + const RealType yp = abs( y ) + sign( y ) * this->phase.y() * this->waveLength.y() / (2.0*M_PI); + const RealType zp = abs( z ) + sign( z ) * this->phase.z() * this->waveLength.z() / (2.0*M_PI); if( ( this->wavesNumber.x() != 0.0 && xp > this->waveLength.x() * this->wavesNumber.x() ) || ( this->wavesNumber.y() != 0.0 && yp > this->waveLength.y() * this->wavesNumber.y() ) || diff --git a/src/TNL/Math.h b/src/TNL/Math.h index ca15bb876d6da3accedb65f7b9c729a0b6d7cda9..e6993069e55cf9a999df56a06588ca13ac5231e3 100644 --- a/src/TNL/Math.h +++ b/src/TNL/Math.h @@ -30,9 +30,8 @@ using both_integral_or_floating = typename std::conditional< // 1. If both types are integral or floating-point, the larger type is selected. // 2. If one type is integral and the other floating-point, the floating-point type is selected. -// This is necessary only due to the limitations of nvcc. Note that clang and gcc -// can handle automatic promotion using a single-type template, exactly like -// std::min and std::max are implemented in STL. +// Casting both arguments to the same type is necessary because std::min and std::max +// are implemented as a single-type template. template< typename T1, typename T2 > using larger_type = typename std::conditional< ( both_integral_or_floating< T1, T2 >::value && sizeof(T1) >= sizeof(T2) ) || diff --git a/src/TNL/Solvers/IterativeSolverMonitor.h b/src/TNL/Solvers/IterativeSolverMonitor.h index 9dec90384a116cf1a9ae79d2cbbd1d6a3a28c47c..3180abb3c34641f7359710dd4e4d8fde44578e77 100644 --- a/src/TNL/Solvers/IterativeSolverMonitor.h +++ b/src/TNL/Solvers/IterativeSolverMonitor.h @@ -18,40 +18,36 @@ namespace Solvers { template< typename Real, typename Index> class IterativeSolverMonitor : public SolverMonitor { - public: - +public: typedef Index IndexType; typedef Real RealType; IterativeSolverMonitor(); + void setStage( const std::string& stage ); + void setTime( const RealType& time ); void setTimeStep( const RealType& timeStep ); - void setStage( const std::string& stage ); - void setIterations( const IndexType& iterations ); void setResidue( const RealType& residue ); void setVerbose( const Index& verbose ); - virtual void refresh( bool force = false ); - - protected: + virtual void refresh(); +protected: int getLineWidth(); - RealType time; - - RealType timeStep; + std::string stage, saved_stage; - std::string stage; + std::atomic_bool saved; - IndexType iterations; + RealType time, saved_time, timeStep, saved_timeStep, residue, saved_residue; - RealType residue; + IndexType iterations, saved_iterations; IndexType verbose; }; diff --git a/src/TNL/Solvers/IterativeSolverMonitor_impl.h b/src/TNL/Solvers/IterativeSolverMonitor_impl.h index 6d9f6bfc7a0846ebacd18ff74bfe3abf0ddf799e..ef18320193dc83007fc87bd4e04e960f95c0ff0e 100644 --- a/src/TNL/Solvers/IterativeSolverMonitor_impl.h +++ b/src/TNL/Solvers/IterativeSolverMonitor_impl.h @@ -13,45 +13,66 @@ #include <iomanip> #include <limits> +// make sure to include the config before the check +#include <TNL/tnlConfig.h> #ifdef HAVE_SYS_IOCTL_H #include <sys/ioctl.h> #include <unistd.h> #endif +#include <TNL/Solvers/IterativeSolver.h> + namespace TNL { namespace Solvers { template< typename Real, typename Index> IterativeSolverMonitor< Real, Index > :: IterativeSolverMonitor() : SolverMonitor(), + stage( "" ), + saved_stage( "" ), + saved( false ), time( 0.0 ), + saved_time( 0.0 ), timeStep( 0.0 ), - stage( "" ), + saved_timeStep( 0.0 ), + residue( 0.0 ), + saved_residue( 0.0 ), iterations( 0 ), - residue( 0 ), + saved_iterations( 0 ), verbose( 1 ) { } template< typename Real, typename Index> -void IterativeSolverMonitor< Real, Index > :: setTime( const RealType& time ) +void IterativeSolverMonitor< Real, Index > :: setStage( const std::string& stage ) { - this->time = time; + // save the items after a complete stage + if( iterations > 0 ) { + saved_stage = this->stage; + saved_time = time; + saved_timeStep = timeStep; + saved_iterations = iterations; + saved_residue = residue; + } + + // reset the current items + iterations = 0; + residue = 0.0; + + this->stage = stage; + saved = true; } template< typename Real, typename Index> -void IterativeSolverMonitor< Real, Index > :: setTimeStep( const RealType& timeStep ) +void IterativeSolverMonitor< Real, Index > :: setTime( const RealType& time ) { - this->timeStep = timeStep; + this->time = time; } template< typename Real, typename Index> -void IterativeSolverMonitor< Real, Index > :: setStage( const std::string& stage ) +void IterativeSolverMonitor< Real, Index > :: setTimeStep( const RealType& timeStep ) { - this->stage = stage; - // reset numerical items displayed after stage - this->iterations = 0; - this->residue = 0.0; + this->timeStep = timeStep; } template< typename Real, typename Index> @@ -73,47 +94,72 @@ void IterativeSolverMonitor< Real, Index > :: setVerbose( const Index& verbose ) } template< typename Real, typename Index> -void IterativeSolverMonitor< Real, Index > :: refresh( bool force ) +void IterativeSolverMonitor< Real, Index > :: refresh() { -// if( this->verbose > 0 && ( force || this->getIterations() % this->refreshRate == 0 ) ) - if( this->verbose > 0 || force ) + if( this->verbose > 0 ) { - const int line_width = this->getLineWidth(); + // Check if we should display the current values or the values saved after + // the previous stage. If the iterations cycle much faster than the solver + // monitor refreshes, we display only the values saved after the whole + // cycle to hide the irrelevant partial progress. + const bool saved = this->saved; + this->saved = false; + + const int line_width = getLineWidth(); int free = line_width ? line_width : std::numeric_limits<int>::max(); - // FIXME: std::setw sets only minimum width, so free should be adjusted dynamically if more chars are actually written - std::cout << std::setprecision( 5 ); - std::cout << "\33[2K\r ELA:" << std::setw( 8 ) << this->getElapsedTime() - << " T:" << std::setw( 8 ) << this->time; - free -= 24; - if( this->timeStep > 0 ) { - std::cout << " TAU:" << std::setw( 8 ) << this->timeStep; - free -= 13; + auto real_to_string = []( Real value, int precision = 6 ) { + std::stringstream stream; + stream << std::setprecision( precision ) << value; + return stream.str(); + }; + + auto print_item = [&free]( const std::string& item, int width = 0 ) { + width = min( free, (width) ? width : item.length() ); + std::cout << std::setw( width ) << item.substr( 0, width ); + free -= width; + }; + + // \33[2K erases the current line, see https://stackoverflow.com/a/35190285 + std::cout << "\33[2K\r"; + + // FIXME: nvcc 8.0 ignores default parameter values for lambda functions in template functions, so we have to pass the defaults +// print_item( " ELA:" ); + print_item( " ELA:", 0 ); + print_item( real_to_string( getElapsedTime(), 5 ), 8 ); +// print_item( " T:" ); + print_item( " T:", 0 ); + print_item( real_to_string( (saved) ? saved_time : time, 5 ), 8 ); + if( (saved) ? saved_timeStep : timeStep > 0 ) { +// print_item( " TAU:" ); + print_item( " TAU:", 0 ); + print_item( real_to_string( (saved) ? saved_timeStep : timeStep, 5 ), 8 ); } - if( this->stage.length() && free > 5 ) { - if( (int) this->stage.length() <= free - 2 ) { - std::cout << " " << this->stage; - free -= ( 2 + this->stage.length() ); + const std::string displayed_stage = (saved) ? saved_stage : stage; + if( displayed_stage.length() && free > 5 ) { + if( (int) displayed_stage.length() <= free - 2 ) { + std::cout << " " << displayed_stage; + free -= ( 2 + displayed_stage.length() ); } else { - std::cout << " " << this->stage.substr( 0, free - 5 ) << "..."; + std::cout << " " << displayed_stage.substr( 0, free - 5 ) << "..."; free = 0; } } - if( this->iterations > 0 && free >= 14 ) { - std::cout << " ITER:" << std::setw( 8 ) << this->iterations; - free -= 14; + if( (saved) ? saved_iterations : iterations > 0 && free >= 14 ) { +// print_item( " ITER:" ); + print_item( " ITER:", 0 ); + print_item( std::to_string( (saved) ? saved_iterations : iterations ), 8 ); } - if( this->residue && free >= 17 ) { - std::cout << " RES:" << std::setprecision( 5 ) << std::setw( 12 ) << this->residue; - free -= 17; + if( (saved) ? saved_residue : residue && free >= 17 ) { +// print_item( " RES:" ); + print_item( " RES:", 0 ); + print_item( real_to_string( (saved) ? saved_residue : residue, 5 ), 12 ); } - // fill the rest of the line with spaces to clear previous content - //while( line_width && free-- > 8 ) - // std::cout << " "; + // return to the beginning of the line std::cout << "\r" << std::flush; } } diff --git a/src/TNL/Solvers/IterativeSolver_impl.h b/src/TNL/Solvers/IterativeSolver_impl.h index da811762ae2b5d1f11f5748e37d52b4026a7f78e..9b98dbea3d308f685d6e9d2acfe701b10f1e270c 100644 --- a/src/TNL/Solvers/IterativeSolver_impl.h +++ b/src/TNL/Solvers/IterativeSolver_impl.h @@ -212,7 +212,6 @@ void IterativeSolver< Real, Index> :: refreshSolverMonitor( bool force ) this->solverMonitor->setIterations( this->getIterations() ); this->solverMonitor->setResidue( this->getResidue() ); this->solverMonitor->setRefreshRate( this-> refreshRate ); -// this->solverMonitor -> refresh( force ); } } diff --git a/src/TNL/Solvers/ODE/ExplicitSolver_impl.h b/src/TNL/Solvers/ODE/ExplicitSolver_impl.h index 11cd7f19285e21d92ddeeb4bcff98897ab59f0d9..352c5ca2b2fee5a6a93ce641114553e0feb662fa 100644 --- a/src/TNL/Solvers/ODE/ExplicitSolver_impl.h +++ b/src/TNL/Solvers/ODE/ExplicitSolver_impl.h @@ -159,7 +159,6 @@ refreshSolverMonitor( bool force ) this->solverMonitor->setTimeStep( this->getTau() ); this->solverMonitor->setTime( this->getTime() ); this->solverMonitor->setRefreshRate( this->refreshRate ); - this->solverMonitor->refresh( force ); } } diff --git a/src/TNL/Solvers/SolverMonitor.h b/src/TNL/Solvers/SolverMonitor.h index 73d78ea4cd458f4e6981d56bf5357d5df6eac3da..124bf1a839f01b720bf35a0a9d2c39d25d3fde22 100644 --- a/src/TNL/Solvers/SolverMonitor.h +++ b/src/TNL/Solvers/SolverMonitor.h @@ -28,7 +28,7 @@ public: timer( nullptr ) {} - virtual void refresh( bool force = false ) = 0; + virtual void refresh() = 0; void setRefreshRate( const int& refreshRate ) { @@ -52,7 +52,7 @@ public: const std::chrono::milliseconds timeout( timeout_base ); while( ! stopped ) { - refresh( true ); + refresh(); // make sure to detect changes to refresh rate int steps = timeout_milliseconds / timeout_base; @@ -90,8 +90,7 @@ protected: std::atomic_int timeout_milliseconds; - std::atomic_bool started; - std::atomic_bool stopped; + std::atomic_bool started, stopped; Timer* timer; }; @@ -121,4 +120,4 @@ class SolverMonitorThread }; } // namespace Solvers -} // namespace TNL \ No newline at end of file +} // namespace TNL diff --git a/src/UnitTests/Containers/ArrayTest.h b/src/UnitTests/Containers/ArrayTest.h index 7b9bc2f5659644199c91c3a291857cc5e18e2564..cd7959b5ff477bb70c1c7be8206e3fc46c38c1f3 100644 --- a/src/UnitTests/Containers/ArrayTest.h +++ b/src/UnitTests/Containers/ArrayTest.h @@ -325,14 +325,15 @@ TYPED_TEST( ArrayTest, elementwiseAccess ) testArrayElementwiseAccess( ArrayType() ); } -// TODO: comparison with different device TYPED_TEST( ArrayTest, comparisonOperator ) { using ArrayType = typename TestFixture::ArrayType; ArrayType u( 10 ), v( 10 ), w( 10 ); + typename ArrayType::HostType u_host( 10 ); for( int i = 0; i < 10; i ++ ) { u.setElement( i, i ); + u_host.setElement( i, i ); v.setElement( i, i ); w.setElement( i, 2 * i ); } @@ -346,6 +347,12 @@ TYPED_TEST( ArrayTest, comparisonOperator ) EXPECT_FALSE( u == w ); EXPECT_FALSE( w == u ); + // comparison with different device + EXPECT_TRUE( u == u_host ); + EXPECT_TRUE( u_host == u ); + EXPECT_TRUE( w != u_host ); + EXPECT_TRUE( u_host != w ); + v.setSize( 0 ); EXPECT_FALSE( u == v ); u.setSize( 0 ); @@ -369,17 +376,30 @@ TYPED_TEST( ArrayTest, comparisonOperatorWithDifferentType ) } */ -// TODO: assignment from different device TYPED_TEST( ArrayTest, assignmentOperator ) { using ArrayType = typename TestFixture::ArrayType; ArrayType u( 10 ), v( 10 ); - for( int i = 0; i < 10; i++ ) + typename ArrayType::HostType u_host( 10 ); + for( int i = 0; i < 10; i++ ) { u.setElement( i, i ); + u_host.setElement( i, i ); + } + v.setValue( 0 ); v = u; EXPECT_EQ( u, v ); + + // assignment from host to device + v.setValue( 0 ); + v = u_host; + EXPECT_EQ( u, v ); + + // assignment from device to host + u_host.setValue( 0 ); + u_host = u; + EXPECT_EQ( u_host, u ); } // test works only for arithmetic types @@ -388,15 +408,36 @@ template< typename ArrayType, void testArrayAssignmentWithDifferentType() { ArrayType u( 10 ); - for( int i = 0; i < 10; i++ ) - u.setElement( i, i ); Array< short, typename ArrayType::DeviceType, short > v( 10 ); + Array< short, Devices::Host, short > v_host( 10 ); + typename ArrayType::HostType u_host( 10 ); + for( int i = 0; i < 10; i++ ) { + u.setElement( i, i ); + u_host.setElement( i, i ); + } + v.setValue( 0 ); v = u; // TODO: missing implementation of relevant reduction operation on CUDA with different types -// EXPECT_EQ( u, v ); +// EXPECT_EQ( v, u ); + for( int i = 0; i < 10; i++ ) + EXPECT_EQ( v.getElement( i ), i ); + + // assignment from host to device + v.setValue( 0 ); + v = u_host; +// TODO: missing implementation of relevant reduction operation on CUDA with different types +// EXPECT_EQ( v, u_host ); for( int i = 0; i < 10; i++ ) EXPECT_EQ( v.getElement( i ), i ); + + // assignment from host to device + v_host.setValue( 0 ); + v_host = u; +// TODO: missing implementation of relevant reduction operation on CUDA with different types +// EXPECT_EQ( v_host, u ); + for( int i = 0; i < 10; i++ ) + EXPECT_EQ( v_host.getElement( i ), i ); } template< typename ArrayType, @@ -406,7 +447,6 @@ void testArrayAssignmentWithDifferentType() { } -// TODO: assignment from different device TYPED_TEST( ArrayTest, assignmentOperatorWithDifferentType ) { using ArrayType = typename TestFixture::ArrayType; diff --git a/src/UnitTests/Containers/StaticArrayTest.cpp b/src/UnitTests/Containers/StaticArrayTest.cpp index d6dedf6236caf347dba2c458e9ef992cfdec5565..dfe99c5876ccc855d8ab62464f59456490e403e2 100644 --- a/src/UnitTests/Containers/StaticArrayTest.cpp +++ b/src/UnitTests/Containers/StaticArrayTest.cpp @@ -212,7 +212,7 @@ TYPED_TEST( StaticArrayTest, AssignmentOperator ) EXPECT_TRUE( u3 != u1 ); // assignment from different type - StaticArray< Size, char > u4( 128 ); + StaticArray< Size, char > u4( 127 ); u3 = u4; EXPECT_TRUE( u3 == u4 ); }