namespace dk { namespace implem { inline CoordinateScalarType sum_mod (CoordinateScalarType parA, CoordinateScalarType parB, CoordinateScalarType parDiv) { //const auto sum = m_pos[index] + parValue; //const auto sz = m_size[index] + 1; //const auto remainder = sum - (sum / sz) * sz; //m_pos[index] = remainder; //parValue /= sz; const auto rounded_sum = sum_div(parA, parB, parDiv) * parDiv; return std::max(parA, parB) - rounded_sum + std::min(parA, parB); } inline CoordinateScalarType sum_div (CoordinateScalarType parA, CoordinateScalarType parB, CoordinateScalarType parDiv) { const auto x = ((parA % parDiv) + (parB % parDiv)) / parDiv; return parA / parDiv + parB / parDiv + x; } } //namespace implem template TileCoords::TileCoords (const coords& parSize) : m_pos(CoordinateScalarType(0)), m_size(parSize) { DK_ASSERT(m_pos <= m_size); DK_ASSERT(m_size < coords(std::numeric_limits::max())); } template TileCoords::TileCoords (const coords& parValue, const coords& parSize) : m_pos(parValue), m_size(parSize) { DK_ASSERT(m_pos <= m_size); DK_ASSERT(m_size < coords(std::numeric_limits::max())); } template TileCoords& TileCoords::operator++ () { const coords lower(0); for (std::size_t d = 0; d < static_cast(D - 1); ++d) { ++m_pos[d]; if (m_pos[d] > m_size[d]) m_pos[d] = lower[d]; else return *this; } ++m_pos[static_cast(D - 1)]; return *this; } template TileCoords TileCoords::operator++ (int) { TileCoords retval(*this); ++(*this); return retval; } template TileCoords& TileCoords::operator-- () { const coords lower(0); for (std::size_t d = 0; d < static_cast(D); ++d) { if (m_pos[d] > lower[d]) { --m_pos[d]; return; } else { m_pos[d] = m_size[d]; } } ++m_pos[static_cast(D - 1)]; return *this; } template TileCoords TileCoords::operator-- (int) { TileCoords retval(*this); --(*this); return retval; } template const TileCoords& TileCoords::operator+= (CoordinateScalarType parValue) { std::size_t index = 0; while (parValue) { //naïve implementation //parValue += m_pos[index]; //m_pos[index] = parValue % (m_size[index] + 1); //parValue /= (m_size[index] + 1); //++index; //overflow-aware implementation const auto new_pos = implem::sum_mod(m_pos[index], parValue, m_size[index] + 1); parValue = implem::sum_div(m_pos[index], parValue, m_size[index] + 1); m_pos[index] = new_pos; } return *this; } template bool TileCoords::operator== (const TileCoords& parOther) const { return m_pos == parOther.m_pos and m_size == parOther.m_size; } template bool TileCoords::operator!= (const TileCoords& parOther) const { return not(*this == parOther); } template const CoordinateScalarType& TileCoords::operator[] (int parIndex) const { DK_ASSERT(parIndex >= 0); DK_ASSERT(static_cast(parIndex) < D); return m_pos[parIndex]; } template CoordinateScalarType& TileCoords::operator[] (int parIndex) { DK_ASSERT(parIndex >= 0); DK_ASSERT(static_cast(parIndex) < D); return m_pos[parIndex]; } } //namespace dk