Skip to content

Commit

Permalink
Merge pull request #106 from dxrcy/const-iters
Browse files Browse the repository at this point in the history
Allow `Chunk`,  `HeightMap` iterators to work when `const`
  • Loading branch information
rozukke authored Dec 10, 2024
2 parents 2f7f223 + 772868d commit 01cde33
Show file tree
Hide file tree
Showing 2 changed files with 231 additions and 0 deletions.
187 changes: 187 additions & 0 deletions include/mcpp/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,102 @@ struct Chunk {
pointer m_ptr;
};

/**
* @brief An iterator for the const Chunk's 3D block data.
*
* This iterator allows for range-based for loops and standard const
* iterator operations over the 3D block data stored within a Chunk. It
* provides a linear interface to traverse the 3D grid of blocks, enabling
* sequential immutable access to the elements stored in the chunk.
*/
struct ConstIterator {
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = BlockType;
using pointer = const BlockType*;
using reference = const BlockType&;

/**
* @brief Constructs an iterator at the given pointer position.
*
* @param ptr Pointer to the position in the height array.
*/
ConstIterator(pointer ptr) : m_ptr(ptr) {}

/**
* @brief Dereference the iterator to access the value at the current
* position.
*
* @return Reference to the current element.
*/
reference operator*() const { return *m_ptr; }

/**
* @brief Access the pointer to the current element.
*
* @return Pointer to the current element.
*/
pointer operator->() { return m_ptr; }

/**
* @brief Pre-increment operator. Advances the iterator to the next
* position.
*
* @return Reference to the updated iterator.
*/
ConstIterator& operator++() {
m_ptr++;
return *this;
}

/**
* @brief Post-increment operator. Advances the iterator to the next
* position.
*
* @param int Unused dummy parameter to differentiate from prefix
* increment.
* @return Iterator to the original position before incrementing.
*/
ConstIterator operator++(int) {
ConstIterator tmp = *this;
++(*this);
return tmp;
}

/**
* @brief Equality comparison operator.
*
* @param a First iterator to compare.
* @param b Second iterator to compare.
* @return true if both iterators point to the same position, false
* otherwise.
*/
friend bool operator==(const ConstIterator& a, const ConstIterator& b) {
return a.m_ptr == b.m_ptr;
};

/**
* @brief Inequality comparison operator.
*
* @param a First iterator to compare.
* @param b Second iterator to compare.
* @return true if iterators point to different positions, false
* otherwise.
*/
friend bool operator!=(const ConstIterator& a, const ConstIterator& b) {
return a.m_ptr != b.m_ptr;
};

private:
pointer m_ptr;
};

Iterator begin() { return Iterator(&raw_data[0]); }
Iterator end() { return Iterator(&raw_data[_x_len * _y_len * _z_len]); }
ConstIterator begin() const { return ConstIterator(&raw_data[0]); }
ConstIterator end() const {
return ConstIterator(&raw_data[_x_len * _y_len * _z_len]);
}

/**
* Initialized by copying from a flat vector of blocks
Expand Down Expand Up @@ -348,8 +442,101 @@ struct HeightMap {
pointer m_ptr;
};

/**
* @brief An iterator for the const HeightMap structure.
*
* This iterator allows for range-based for loops and standard const
* iterator operations over the height data stored within a HeightMap.
*/
struct ConstIterator {
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = int;
using pointer = const int*;
using reference = const int&;

/**
* @brief Constructs an iterator at the given pointer position.
*
* @param ptr Pointer to the position in the height array.
*/
ConstIterator(pointer ptr) : m_ptr(ptr) {}

/**
* @brief Dereference the iterator to access the value at the current
* position.
*
* @return Reference to the current element.
*/
reference operator*() const { return *m_ptr; }

/**
* @brief Access the pointer to the current element.
*
* @return Pointer to the current element.
*/
pointer operator->() { return m_ptr; }

/**
* @brief Pre-increment operator. Advances the iterator to the next
* position.
*
* @return Reference to the updated iterator.
*/
ConstIterator& operator++() {
m_ptr++;
return *this;
}

/**
* @brief Post-increment operator. Advances the iterator to the next
* position.
*
* @param int Unused dummy parameter to differentiate from prefix
* increment.
* @return Iterator to the original position before incrementing.
*/
ConstIterator operator++(int) {
ConstIterator tmp = *this;
++(*this);
return tmp;
}

/**
* @brief Equality comparison operator.
*
* @param a First iterator to compare.
* @param b Second iterator to compare.
* @return true if both iterators point to the same position, false
* otherwise.
*/
friend bool operator==(const ConstIterator& a, const ConstIterator& b) {
return a.m_ptr == b.m_ptr;
};

/**
* @brief Inequality comparison operator.
*
* @param a First iterator to compare.
* @param b Second iterator to compare.
* @return true if iterators point to different positions, false
* otherwise.
*/
friend bool operator!=(const ConstIterator& a, const ConstIterator& b) {
return a.m_ptr != b.m_ptr;
};

private:
pointer m_ptr;
};

Iterator begin() { return Iterator(&raw_heights[0]); }
Iterator end() { return Iterator(&raw_heights[_x_len * _z_len]); }
ConstIterator begin() const { return ConstIterator(&raw_heights[0]); }
ConstIterator end() const {
return ConstIterator(&raw_heights[_x_len * _z_len]);
}

HeightMap(const Coordinate& loc1, const Coordinate& loc2,
const std::vector<int>& heights);

Expand Down
44 changes: 44 additions & 0 deletions test/minecraft_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ TEST_CASE("getBlocks and Chunk operations") {
mc.setBlock(loc2, Blocks::DIAMOND_BLOCK);
mc.setBlock(loc1 + Coordinate{1, 2, 3}, Blocks::IRON_BLOCK);
Chunk res = mc.getBlocks(loc1, loc2);
const Chunk res_const = mc.getBlocks(loc1, loc2);

SUBCASE("getters") {
Chunk data = mc.getBlocks(loc1, loc2);
Expand Down Expand Up @@ -201,6 +202,23 @@ TEST_CASE("getBlocks and Chunk operations") {
CHECK_EQ(blocks, expected_blocks);
}

SUBCASE("Const iterator") {
std::vector<BlockType> blocks;
for (int i = 0; i < res_const.y_len(); i++) {
for (int j = 0; j < res_const.x_len(); j++) {
for (int z = 0; z < res_const.z_len(); z++) {
blocks.push_back(res_const.get(j, i, z));
}
}
}

std::vector<BlockType> expected_blocks;
for (BlockType block : res_const) {
expected_blocks.push_back(block);
}
CHECK_EQ(blocks, expected_blocks);
}

mc.setBlock(test_loc, BlockType(0));
}

Expand Down Expand Up @@ -325,6 +343,32 @@ TEST_CASE("HeightMap functionality") {
CHECK_EQ(heights, expected_heights);
}

SUBCASE("Const iterator") {
mc.setBlocks(Coordinate{-200, 300, -200}, Coordinate{-210, 319, -210},
Blocks::AIR);
mc.setBlocks(Coordinate{-200, 300, -200}, Coordinate{-210, 300, -210},
Blocks::STONE);
mc.setBlock(Coordinate{-200, 301, -200}, Blocks::STONE);
mc.setBlock(Coordinate{-210, 301, -210}, Blocks::STONE);
mc.setBlock(Coordinate{-201, 301, -202}, Blocks::STONE);

const HeightMap data =
mc.getHeights(Coordinate{-200, 0, -200}, Coordinate{-210, 0, -210});

std::vector<int> expected_heights;
for (int i = 0; i < data.x_len(); i++) {
for (int j = 0; j < data.z_len(); j++) {
expected_heights.push_back(data.get(i, j));
}
}

std::vector<int> heights;
for (int height : data) {
heights.push_back(height);
}
CHECK_EQ(heights, expected_heights);
}

// Clean up
mc.setBlocks(Coordinate{200, 300, 200}, Coordinate{210, 301, 210},
Blocks::AIR);
Expand Down

0 comments on commit 01cde33

Please sign in to comment.