Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions include/intersection/detail.hh
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "distance/distance.hh"
#include "primitives/primitives.hh"
#include "primitives/vec2.hh"
#include "utils/utils.hh"

namespace geom::detail
{
Expand Down Expand Up @@ -128,10 +129,9 @@ Segment2D<T> helperMollerHaines(const Triangle<T> &tr, const Plane<T> &pl, const
std::size_t rogue = roguePos(sdist.begin(), sdist.end());

std::array<T, 2> segm{};
std::array<size_t, 2> arr{(rogue + 1) % 3, (rogue + 2) % 3};
std::transform(arr.begin(), arr.end(), segm.begin(), [&vert, &sdist, rogue](auto i) {
return vert[i] + (vert[rogue] - vert[i]) * sdist[i] / (sdist[i] - sdist[rogue]);
});
std::array<std::size_t, 2> arr = {(rogue + 1) % 3, (rogue + 2) % 3};
for (auto [idx, i] : utils::Enumerate(arr))
segm[idx] = vert[i] + (vert[rogue] - vert[i]) * sdist[i] / (sdist[i] - sdist[rogue]);

return std::minmax(segm[0], segm[1]);
}
Expand Down
137 changes: 137 additions & 0 deletions include/utils/utils.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
#ifndef __INCLUDE_UTILS_UTILS_HH__
#define __INCLUDE_UTILS_UTILS_HH__

#include <cassert>
#include <concepts>
#include <iterator>

namespace utils
{
template <class T>
concept ItContainer = requires(T cont)
{
{
std::begin(cont)
} -> std::forward_iterator;
{
std::end(cont)
} -> std::forward_iterator;
{
std::size(cont)
} -> std::convertible_to<std::size_t>;
};

namespace detail
{
template <std::forward_iterator It>
class EnumerateIt final
{
private:
template <typename Ref>
struct ArrowProxy
{
Ref r;

Ref *operator->()
{
return &r;
}
};

public:
using iterator_category = std::forward_iterator_tag;
using difference_type =
std::pair<std::make_signed_t<std::size_t>, typename std::iterator_traits<It>::difference_type>;
Comment on lines +43 to +44
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it really should be a pair? Maybe just number is enough?

using value_type = std::pair<std::size_t, typename std::iterator_traits<It>::value_type>;
using reference = std::pair<std::size_t, typename std::iterator_traits<It>::reference>;
using pointer = ArrowProxy<reference>;

private:
std::size_t counter_;
It iter_;

public:
EnumerateIt(std::size_t i, It iter) : counter_(i), iter_(iter)
{}

reference operator*() const
{
return {counter_, *iter_};
}

EnumerateIt &operator++()
{
++counter_;
++iter_;
return *this;
}

EnumerateIt operator++(int)
{
auto temp{*this};
operator++();
return temp;
}

bool equals(const EnumerateIt &rhs) const
{
return iter_ == rhs.iter_;
}

pointer operator->() const
{
return pointer{{counter_, *iter_}};
}
};

template <std::forward_iterator It>
bool operator==(const EnumerateIt<It> &lhs, const EnumerateIt<It> &rhs)
{
return lhs.equals(rhs);
}
} // namespace detail

template <ItContainer C>
class Enumerate final
{
private:
using NoRefC = std::remove_reference_t<C>;
using ContStorageType = std::conditional_t<std::is_rvalue_reference_v<C>, NoRefC, NoRefC &>;

ContStorageType cont_;
using EnumItType = detail::EnumerateIt<decltype(std::begin(cont_))>;

public:
Enumerate(C &&cont) : cont_(std::forward<C>(cont))
{}

auto begin()
{
return EnumItType(0, std::begin(cont_));
}
auto begin() const
{
return EnumItType(0, std::begin(cont_));
}

auto end()
{
return EnumItType(std::size(cont_), std::end(cont_));
}
auto end() const
{
return EnumItType(std::size(cont_), std::end(cont_));
}

auto size() const
{
return std::size(cont_);
}
};

template <ItContainer C>
Enumerate(C &&) -> Enumerate<C &&>;

} // namespace utils

#endif /* __INCLUDE_UTILS_UTILS_HH__ */
2 changes: 1 addition & 1 deletion lib/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
set(LIBLIST primitives intersection distance kdtree)
set(LIBLIST primitives intersection distance kdtree utils)

foreach(LIB ${LIBLIST})
add_subdirectory(${LIB})
Expand Down
4 changes: 4 additions & 0 deletions lib/utils/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
add_library(utils INTERFACE)
target_sources(utils
INTERFACE ${CMAKE_SOURCE_DIR}/include/utils/utils.hh
)
188 changes: 188 additions & 0 deletions test/unit/utils.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
#include "utils/utils.hh"

#include "test_header.hh"
#include <algorithm>
#include <numeric>
#include <vector>

using namespace utils;

TEST(EnumerateTest, ordVecSimpleBind)
{
// Arrange
std::vector<int> vec;
vec.resize(10);
std::iota(vec.begin(), vec.end(), 0);

// Act && Asserts
for (auto val : Enumerate(vec))
ASSERT_EQ(val.first, val.second);
}

TEST(EnumerateTest, ordVecStructBind)
{
// Arrange
std::vector<int> vec;
vec.resize(10);
std::iota(vec.begin(), vec.end(), 0);

// Act && Asserts
for (auto [i, val] : Enumerate(vec))
ASSERT_EQ(i, val);
}

TEST(EnumerateTest, ordVecChangeValue)
{
// Arrange
std::vector<int> vec, expect;
vec.resize(10);
expect.resize(vec.size());
std::iota(vec.begin(), vec.end(), 0);
std::iota(expect.rbegin(), expect.rend(), -expect.size() + 1);

// Act
for (auto [i, val] : Enumerate(vec))
val = -static_cast<int>(i);

// Assert
EXPECT_EQ(vec, expect);
}

TEST(EnumerateTest, twiceDeref)
{
// Arrange
std::vector<int> vec = {1, 2, 3};

// Act
auto enumerate = Enumerate(vec);
auto it1 = enumerate.begin();
auto it2 = enumerate.begin();

using value_type =
std::iterator_traits<detail::EnumerateIt<std::vector<int>::iterator>>::value_type;

value_type v1 = *it1++;
value_type v2 = *it1;

auto r1 = *it2;
++it2;
auto r2 = *it2;

// Assert
EXPECT_EQ(v1.first, 0);
EXPECT_EQ(v2.first, 1);

EXPECT_NE(r1, r2);
}

TEST(EnumerateTest, ordVecTemp)
{
// Arrange
std::vector<int> res, expect(10, 10);
res.resize(10);

// Act
for (auto [i, val] : Enumerate(std::vector<int>(expect.size(), 10)))
res[i] = val;

// Assert
EXPECT_EQ(res, expect);
}

TEST(EnumerateTest, arrowProxy)
{
// Arrange
struct Compl
{
int a;

Compl &operator=(int v)
{
a = v;
return *this;
}

bool operator==(const Compl &) const = default;

void inc()
{
a++;
}
};

std::vector<Compl> vec, expect;
vec.resize(10);
expect.resize(vec.size());
std::iota(vec.begin(), vec.end(), 0);
std::iota(expect.begin(), expect.end(), 1);

// Act
auto enumerate = Enumerate(vec);
for (auto it = enumerate.begin(); it != enumerate.end(); it++)
it->second.inc();

// Assert
EXPECT_EQ(vec, expect);
}

TEST(EnumerateTest, constContainer)
{
// Arrange
const std::vector vec = {1, 2, 3, 4, 5};
std::vector<int> vec2(vec.size());

// Act
for (auto [idx, val] : Enumerate(vec))
vec2[idx] = val;

// Assert
EXPECT_EQ(vec, vec2);
}

TEST(EnumerateTest, MoveSemantics)
{
// Arrange
struct WasMovedType
{};
struct WasCopiedType
{};
struct ToMove
{
private:
std::vector<int> dummy{};

public:
ToMove() = default;

ToMove(const ToMove &that) : dummy(that.dummy)
{
throw WasCopiedType{};
}
ToMove(ToMove &&that) : dummy(std::move(that.dummy))
{
throw WasMovedType{};
}

auto size() const
{
return dummy.size();
}

auto begin()
{
return dummy.begin();
}

auto end()
{
return dummy.end();
}
};

ToMove local;
// Act && Assert
EXPECT_THROW([[maybe_unused]] auto moved = Enumerate(ToMove{});, WasMovedType);
EXPECT_NO_THROW([[maybe_unused]] auto copied = Enumerate(local););
}

#include "test_footer.hh"