I'm lazy, or just tired of writing the same shizz over and over anyway. So, I figured why not create some algorithms that loosely mimic the STL.
Copying one 2d array to another
Code: Select all
template<typename Cont1, typename Cont2, typename RectType>
void copy2d( const RectType& _bounds, const Cont1& _source, Cont2& _dest )
{
using type_1 = typename Cont1::value_type;
using type_2 = typename Cont2::value_type;
static_assert( std::is_same_v<type_1,type_2>,
"Container::value_type must be the same for both containers."
);
const auto width = _bounds.Width();
for( int y = _bounds.Top(); y < _bounds.Bottom(); ++y )
{
if constexpr( std::is_trivially_copyable_v<type_1> )
{
memcpy( std::addressof( _dest( 0, y ) ), std::addressof( _source( 0, y ) ), sizeof( type_1 ) * width );
}
else
{
for( int x = _bounds.Left(); x < _bounds.Right(); ++x )
{
_dest( x, y ) = _source( x, y );
}
}
}
}
Code: Select all
template<typename Cont1, typename Cont2, typename RectType>
void copy2d( const RectType& _srcBounds, const RectType& _dstBounds, const Cont1& _source, Cont2& _dest )
{
using type_1 = typename Cont1::value_type;
using type_2 = typename Cont2::value_type;
static_assert( std::is_same_v<type_1, type_2>,
"Container::value_type must be the same for both containers."
);
assert(
_srcBounds.Width() == _dstBounds.Width() &&
_srcBounds.Height() == _dstBounds.Height() &&
"Source and destination RectTypes must be same dimensions." );
const auto stride = sizeof( type_1 ) * _srcBounds.Width();
for( int y = _srcBounds.Top(); y < _srcBounds.Bottom(); ++y )
{
const auto srcy = y + _srcBounds.Top();
const auto dsty = y + _dstBounds.Top();
if constexpr( std::is_trivially_copyable_v<type_1> )
{
auto* dst = std::addressof( _dest( _dstBounds.Left(), dsty ) );
auto const* src = std::addressof( _source( _srcBounds.Left(), srcy ) );
memcpy( dst, src, stride );
}
else
{
for( int x = _srcBounds.Left(); x < _srcBounds.Right(); ++x )
{
for( int x = 0; x < _srcBounds.Width(); ++x )
{
const auto srcx = x + _srcBounds.Left();
const auto dstx = x + _dstBounds.Left();
_dest( dstx, dsty ) = _source( srcx, srcy );
}
}
}
}
}
Code: Select all
template<typename Cont1, typename Cont2, typename RectType, typename Pred>
void copy2d_if(
const RectType& _srcBounds, const RectType& _dstBounds, const Cont1& _source, Cont2& _dest,
Pred&& _pred )
{
using type_1 = typename Cont1::value_type;
using type_2 = typename Cont2::value_type;
static_assert( std::is_same_v<type_1, type_2>,
"Container::value_type must be the same for both containers."
);
assert(
_srcBounds.Width() == _dstBounds.Width() &&
_srcBounds.Height() == _dstBounds.Height() &&
"Source and destination RectTypes must be same dimensions." );
for( int y = 0; y < _srcBounds.Height(); ++y )
{
const auto srcy = y + _srcBounds.Top();
const auto dsty = y + _dstBounds.Top();
for( int x = 0; x < _srcBounds.Width(); ++x )
{
const auto srcx = x + _srcBounds.Left();
const auto dstx = x + _dstBounds.Left();
if( const auto& elem = _source( srcx, srcy ); _pred( elem ) )
_dest( dstx, dsty ) = elem;
}
}
}
Code: Select all
template<typename Cont, typename RectType, typename Func>
void for_each2d( const RectType& _bounds, Cont& _container, Func&& _func )
{
for( std::int32_t y = _bounds.Top(); y < _bounds.Bottom(); ++y )
{
for( std::int32_t x = _bounds.Left(); x < _bounds.Right(); ++x )
{
_func( _container( x, y ) );
}
}
}
Code: Select all
template<typename Cont, typename RectType>
void fill2d( const typename Cont::value_type& _value, const RectType& _bounds, Cont& _container )
{
for( int y = _bounds.Top(); y < _bounds.Bottom(); ++y )
{
for( int x = _bounds.Left(); x < _bounds.Right(); ++x )
{
_container( x, y ) = _value;
}
}
}
Code: Select all
template<typename Cont, typename RectType, typename Generator>
void generate2d( const RectType& _bounds, Cont& _cont, Generator&& _generate )
{
for( int y = _bounds.Top(); y < _bounds.Bottom(); ++y )
{
for( int x = _bounds.Left(); x < _bounds.Right(); ++x )
{
_cont( x, y ) = _generate();
}
}
}
Code: Select all
template<typename Cont1, typename Cont2, typename RectType>
void replace2d(
const typename Cont1::value_type& _replace_value,
const typename Cont2::value_type& _with_value,
const RectType& _srcBounds,
const RectType& _dstBounds,
const Cont1& _src,
Cont2& _dst)
{
using type_1 = typename Cont1::value_type;
using type_2 = typename Cont2::value_type;
static_assert( std::is_same_v<type_1, type_2>,
"Container::value_type must be the same for both containers."
);
assert(
_srcBounds.Width() == _dstBounds.Width() &&
_srcBounds.Height() == _dstBounds.Height() &&
"Source and destination RectTypes must be same dimensions." );
for( int y = 0; y < _srcBounds.height; ++y )
{
const auto srcy = y + _srcBounds.Top();
const auto dsty = y + _dstBounds.Top();
for( int x = 0; x < _srcBounds.width; ++x )
{
const auto srcx = x + _srcBounds.Left();
const auto dstx = x + _dstBounds.Left();
if( _src( srcx, srcy ) == _replace_value )
_dst( dstx, dsty ) = _with_value;
}
}
}
Code: Select all
template<typename Cont1, typename Cont2, typename RectType, typename Pred>
void replace2d_if(
const typename Cont1::value_type& _new_value,
const RectType& _srcBounds,
const RectType& _dstBounds,
const Cont1& _src,
Cont2& _dst,
Pred&& _pred )
{
assert(
_srcBounds.Width() == _dstBounds.Width() &&
_srcBounds.Height() == _dstBounds.Height() &&
"Source and destination RectTypes must be same dimensions." );
for( int y = 0; y < _srcBounds.height; ++y )
{
const auto srcy = y + _srcBounds.Top();
const auto dsty = y + _dstBounds.Top();
for( int x = 0; x < _srcBounds.width; ++x )
{
const auto srcx = x + _srcBounds.Left();
const auto dstx = x + _dstBounds.Left();
const auto& srcElement = _src( srcx, srcy );
auto& dstElement = _dst( dstx, dsty );
if( _pred( srcElement, dstElement ) )
{
dstElement = _new_value;
}
}
}
}
Code: Select all
template<typename Cont1, typename Cont2, typename RectType, typename Func>
void transform2d(
const RectType& _srcBounds, const RectType& _dstBounds,
const Cont1& _src, Cont2& _dst, Func&& _func )
{
using type_1 = typename Cont1::value_type;
using type_2 = typename Cont2::value_type;
static_assert( std::is_same_v<type_1, type_2>,
"Container::value_type must be the same for both containers."
);
assert(
_srcBounds.Width() == _dstBounds.Width() &&
_srcBounds.Height() == _dstBounds.Height() &&
"Source and destination RectTypes must be same dimensions." );
for( int y = 0; y < _srcBounds.height; ++y )
{
const auto srcy = y + _srcBounds.Top();
const auto dsty = y + _dstBounds.Top();
for( int x = 0; x < _srcBounds.width; ++x )
{
const auto srcx = x + _srcBounds.Left();
const auto dstx = x + _dstBounds.Left();
_dst( dstx, dsty ) = _func( _src( srcx, srcy ) );
}
}
}
Code: Select all
template<typename Cont1, typename Cont2, typename Cont3, typename RectType, typename Func>
void transform2d(
const RectType& _srcBounds1, const RectType& _srcBounds2, const RectType& _dstBounds,
const Cont1& _src1, const Cont1& _src2, Cont2& _dst, Func&& _func )
{
using type_1 = typename Cont1::value_type;
using type_2 = typename Cont2::value_type;
using type_3 = typename Cont3::value_type;
static_assert( std::conjunction_v<std::is_same<type_1, type_2>,std::is_same<type_2, type_3>>,
"Container::value_type must be the same for all three containers."
);
assert(
_srcBounds1.Width() == _dstBounds.Width() &&
_srcBounds1.Height() == _dstBounds.Height() &&
_srcBounds2.Width() == _srcBounds1.Width() &&
_srcBounds2.Height() == _srcBounds1.Height() &&
"Source and destination RectTypes must be same dimensions." );
for( int y = 0; y < _srcBounds.height; ++y )
{
const auto srcy1 = y + _srcBounds1.Top();
const auto srcy2 = y + _srcBounds2.Top();
const auto dsty = y + _dstBounds.Top();
for( int x = 0; x < _srcBounds.width; ++x )
{
const auto srcx1 = x + _srcBounds1.Left();
const auto srcx2 = x + _srcBounds2.Left();
const auto dstx = x + _dstBounds.Left();
_dst( dstx, dsty ) = _func( _src1( srcx1, srcy1 ), _src2( srcx2, srcy2 ) );
}
}
}