2015-07-29 23:18:19 +00:00
|
|
|
namespace dk {
|
2015-08-14 16:18:43 +00:00
|
|
|
namespace implem {
|
2015-08-14 20:13:14 +00:00
|
|
|
///----------------------------------------------------------------------
|
|
|
|
///Equivalent to (parA + parB) % parDiv
|
|
|
|
///----------------------------------------------------------------------
|
2015-08-14 16:18:43 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2015-08-14 20:13:14 +00:00
|
|
|
///----------------------------------------------------------------------
|
|
|
|
///Equivalent to (parA + parB) / parDiv
|
|
|
|
///----------------------------------------------------------------------
|
2015-08-14 16:18:43 +00:00
|
|
|
inline CoordinateScalarType sum_div (CoordinateScalarType parA, CoordinateScalarType parB, CoordinateScalarType parDiv) {
|
2015-08-16 14:34:32 +00:00
|
|
|
DK_ASSERT(parA >= 0 and parB >= 0 and parDiv > 0);
|
|
|
|
DK_ASSERT(std::numeric_limits<CoordinateScalarType>::max() - (parA % parDiv) >= (parB % parDiv));
|
2015-08-14 16:18:43 +00:00
|
|
|
const auto x = ((parA % parDiv) + (parB % parDiv)) / parDiv;
|
2015-08-16 14:34:32 +00:00
|
|
|
DK_ASSERT(std::numeric_limits<CoordinateScalarType>::max() - parA / parDiv >= parB / parDiv);
|
|
|
|
DK_ASSERT(std::numeric_limits<CoordinateScalarType>::max() - parA / parDiv - parB / parDiv >= x);
|
2015-08-14 16:18:43 +00:00
|
|
|
return parA / parDiv + parB / parDiv + x;
|
|
|
|
}
|
2015-08-16 14:34:32 +00:00
|
|
|
|
|
|
|
inline CoordinateScalarType sub_mod (CoordinateScalarType parA, CoordinateScalarType parB, CoordinateScalarType parDiv) {
|
|
|
|
typedef std::make_unsigned<CoordinateScalarType>::type unsigned_coord;
|
|
|
|
const unsigned_coord rounded_sum = static_cast<unsigned_coord>(sub_div(parA, parB, parDiv) * parDiv);
|
|
|
|
const unsigned_coord ret = static_cast<unsigned_coord>(parA) - rounded_sum - static_cast<unsigned_coord>(parB);
|
|
|
|
return static_cast<CoordinateScalarType>(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline CoordinateScalarType sub_div (CoordinateScalarType parA, CoordinateScalarType parB, CoordinateScalarType parDiv) {
|
|
|
|
const auto x = ((parA % parDiv) + (parB % parDiv)) / parDiv;
|
|
|
|
return parA / parDiv - parB / parDiv + x;
|
|
|
|
}
|
2015-08-14 16:18:43 +00:00
|
|
|
} //namespace implem
|
|
|
|
|
2015-07-29 23:18:19 +00:00
|
|
|
template <uint32_t D>
|
|
|
|
TileCoords<D>::TileCoords (const coords& parSize) :
|
|
|
|
m_pos(CoordinateScalarType(0)),
|
|
|
|
m_size(parSize)
|
|
|
|
{
|
2015-08-14 10:30:27 +00:00
|
|
|
DK_ASSERT(m_pos <= m_size);
|
2015-08-14 16:18:43 +00:00
|
|
|
DK_ASSERT(m_size < coords(std::numeric_limits<CoordinateScalarType>::max()));
|
2015-07-29 23:18:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <uint32_t D>
|
|
|
|
TileCoords<D>::TileCoords (const coords& parValue, const coords& parSize) :
|
|
|
|
m_pos(parValue),
|
|
|
|
m_size(parSize)
|
|
|
|
{
|
2015-08-14 10:30:27 +00:00
|
|
|
DK_ASSERT(m_pos <= m_size);
|
2015-08-14 16:18:43 +00:00
|
|
|
DK_ASSERT(m_size < coords(std::numeric_limits<CoordinateScalarType>::max()));
|
2015-07-29 23:18:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <uint32_t D>
|
|
|
|
TileCoords<D>& TileCoords<D>::operator++ () {
|
|
|
|
const coords lower(0);
|
2015-08-14 10:31:13 +00:00
|
|
|
for (std::size_t d = 0; d < static_cast<std::size_t>(D - 1); ++d) {
|
2015-07-29 23:18:19 +00:00
|
|
|
++m_pos[d];
|
2015-07-30 00:04:02 +00:00
|
|
|
if (m_pos[d] > m_size[d])
|
2015-07-29 23:18:19 +00:00
|
|
|
m_pos[d] = lower[d];
|
|
|
|
else
|
|
|
|
return *this;
|
|
|
|
}
|
2015-08-14 10:31:13 +00:00
|
|
|
++m_pos[static_cast<std::size_t>(D - 1)];
|
2015-07-29 23:18:19 +00:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <uint32_t D>
|
|
|
|
TileCoords<D> TileCoords<D>::operator++ (int) {
|
|
|
|
TileCoords<D> retval(*this);
|
|
|
|
++(*this);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <uint32_t D>
|
|
|
|
TileCoords<D>& TileCoords<D>::operator-- () {
|
|
|
|
const coords lower(0);
|
2015-08-14 10:31:13 +00:00
|
|
|
for (std::size_t d = 0; d < static_cast<std::size_t>(D); ++d) {
|
2015-07-29 23:18:19 +00:00
|
|
|
if (m_pos[d] > lower[d]) {
|
|
|
|
--m_pos[d];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
m_pos[d] = m_size[d];
|
|
|
|
}
|
|
|
|
}
|
2015-08-14 10:31:13 +00:00
|
|
|
++m_pos[static_cast<std::size_t>(D - 1)];
|
2015-07-29 23:18:19 +00:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <uint32_t D>
|
|
|
|
TileCoords<D> TileCoords<D>::operator-- (int) {
|
|
|
|
TileCoords<D> retval(*this);
|
|
|
|
--(*this);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2015-08-16 14:34:32 +00:00
|
|
|
template <uint32_t D>
|
|
|
|
const TileCoords<D>& TileCoords<D>::operator-= (CoordinateScalarType parValue) {
|
|
|
|
std::size_t index = 0;
|
|
|
|
if (parValue > 0) {
|
|
|
|
while (parValue) {
|
|
|
|
const auto t = parValue % (m_size[index] + 1);
|
|
|
|
DK_ASSERT(t >= 0);
|
|
|
|
const CoordinateScalarType r = (t > m_pos[index] ? 1 : 0);
|
|
|
|
m_pos[index] = (m_size[index] + 1) * r + m_pos[index] - t;
|
|
|
|
parValue /= (m_size[index] + 1);
|
|
|
|
parValue += r;
|
|
|
|
|
|
|
|
++index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (parValue < 0) {
|
|
|
|
while (parValue) {
|
|
|
|
const auto new_pos = implem::sub_mod(m_pos[index], parValue, m_size[index] + 1);
|
|
|
|
parValue = -implem::sub_div(m_pos[index], parValue, m_size[index] + 1);
|
|
|
|
m_pos[index] = new_pos;
|
|
|
|
|
|
|
|
++index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2015-07-29 23:18:19 +00:00
|
|
|
template <uint32_t D>
|
|
|
|
const TileCoords<D>& TileCoords<D>::operator+= (CoordinateScalarType parValue) {
|
2015-08-14 16:18:43 +00:00
|
|
|
std::size_t index = 0;
|
2015-08-15 21:52:37 +00:00
|
|
|
if (parValue > 0) {
|
|
|
|
while (parValue) {
|
|
|
|
//naïve implementation
|
|
|
|
//parValue += m_pos[index];
|
|
|
|
//m_pos[index] = parValue % (m_size[index] + 1);
|
|
|
|
//parValue /= (m_size[index] + 1);
|
|
|
|
|
|
|
|
//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;
|
|
|
|
|
|
|
|
++index;
|
|
|
|
}
|
2015-07-29 23:18:19 +00:00
|
|
|
}
|
2015-08-15 21:52:37 +00:00
|
|
|
else if (parValue < 0) {
|
|
|
|
while (parValue) {
|
|
|
|
//const auto t = (-parValue) % (m_size[index] + 1);
|
|
|
|
const auto t = -(parValue % (m_size[index] + 1));
|
|
|
|
DK_ASSERT(t >= 0);
|
|
|
|
const CoordinateScalarType r = (t > m_pos[index] ? 1 : 0);
|
|
|
|
m_pos[index] = (m_size[index] + 1) * r + m_pos[index] - t;
|
|
|
|
parValue /= (m_size[index] + 1);
|
|
|
|
parValue -= r;
|
|
|
|
|
|
|
|
++index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-14 16:18:43 +00:00
|
|
|
return *this;
|
2015-07-29 23:18:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <uint32_t D>
|
|
|
|
bool TileCoords<D>::operator== (const TileCoords& parOther) const {
|
|
|
|
return m_pos == parOther.m_pos and m_size == parOther.m_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <uint32_t D>
|
|
|
|
bool TileCoords<D>::operator!= (const TileCoords& parOther) const {
|
|
|
|
return not(*this == parOther);
|
|
|
|
}
|
2015-08-14 16:18:43 +00:00
|
|
|
|
|
|
|
template <uint32_t D>
|
|
|
|
const CoordinateScalarType& TileCoords<D>::operator[] (int parIndex) const {
|
|
|
|
DK_ASSERT(parIndex >= 0);
|
|
|
|
DK_ASSERT(static_cast<uint32_t>(parIndex) < D);
|
|
|
|
return m_pos[parIndex];
|
|
|
|
}
|
|
|
|
template <uint32_t D>
|
|
|
|
CoordinateScalarType& TileCoords<D>::operator[] (int parIndex) {
|
|
|
|
DK_ASSERT(parIndex >= 0);
|
|
|
|
DK_ASSERT(static_cast<uint32_t>(parIndex) < D);
|
|
|
|
return m_pos[parIndex];
|
|
|
|
}
|
2015-08-16 14:34:32 +00:00
|
|
|
|
|
|
|
template <uint32_t D>
|
|
|
|
auto TileCoords<D>::position() const -> const coords& {
|
|
|
|
return m_pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <uint32_t D>
|
|
|
|
auto TileCoords<D>::upper() const -> const coords& {
|
|
|
|
return m_size;
|
|
|
|
}
|
2015-07-29 23:18:19 +00:00
|
|
|
} //namespace dk
|