Skip to content
Snippets Groups Projects
Commit 99cb1d48 authored by Ben Cumming's avatar Ben Cumming Committed by GitHub
Browse files

Merge pull request #10 from halfflat/bugfix/sort-ranges

Can't std::sort on forward iterators.
parents 316366cd a50de751
No related branches found
No related tags found
No related merge requests found
......@@ -151,6 +151,9 @@ range<U, V> make_range(const U& left, const V& right) {
return range<U, V>(left, right);
}
// Present a possibly sentinel-terminated range as an STL-compatible sequence
// using the sentinel_iterator adaptor.
template <typename Seq>
auto canonical_view(Seq& s) ->
range<sentinel_iterator_t<decltype(std::begin(s)), decltype(std::end(s))>>
......@@ -165,6 +168,21 @@ auto canonical_view(const Seq& s) ->
return {make_sentinel_iterator(std::begin(s), std::end(s)), make_sentinel_end(std::begin(s), std::end(s))};
}
// Strictly evaluate end point in sentinel-terminated range and present as a range over
// iterators. Note: O(N) behaviour with forward iterator ranges or sentinel-terminated ranges.
template <typename Seq>
auto strict_view(Seq& s) -> range<decltype(std::begin(s))>
{
return make_range(std::begin(s), std::next(util::upto(std::begin(s), std::end(s))));
}
template <typename Seq>
auto strict_view(const Seq& s) -> range<decltype(std::begin(s))>
{
return make_range(std::begin(s), std::next(util::upto(std::begin(s), std::end(s))));
}
} // namespace util
} // namespace mc
} // namespace nest
......@@ -75,9 +75,18 @@ AssignableContainer& assign_by(AssignableContainer& c, const Seq& seq, const Pro
}
// Sort in-place
// Note that a const range reference may wrap non-const iterators.
template <typename Seq>
void sort(Seq& seq) {
enable_if_t<!std::is_const<typename util::sequence_traits<Seq>::reference>::value>
sort(Seq& seq) {
auto canon = canonical_view(seq);
std::sort(std::begin(canon), std::end(canon));
}
template <typename Seq>
enable_if_t<!std::is_const<typename util::sequence_traits<Seq>::reference>::value>
sort(const Seq& seq) {
auto canon = canonical_view(seq);
std::sort(std::begin(canon), std::end(canon));
}
......@@ -85,7 +94,20 @@ void sort(Seq& seq) {
// Sort in-place by projection `proj`
template <typename Seq, typename Proj>
void sort_by(Seq& seq, const Proj& proj) {
enable_if_t<!std::is_const<typename util::sequence_traits<Seq>::reference>::value>
sort_by(Seq& seq, const Proj& proj) {
using value_type = typename sequence_traits<Seq>::value_type;
auto canon = canonical_view(seq);
std::sort(std::begin(canon), std::end(canon),
[&proj](const value_type& a, const value_type& b) {
return proj(a) < proj(b);
});
}
template <typename Seq, typename Proj>
enable_if_t<!std::is_const<typename util::sequence_traits<Seq>::reference>::value>
sort_by(const Seq& seq, const Proj& proj) {
using value_type = typename sequence_traits<Seq>::value_type;
auto canon = canonical_view(seq);
......
set(HEADERS
${PROJECT_SOURCE_DIR}/src/cell.hpp
${PROJECT_SOURCE_DIR}/src/cell_tree.hpp
${PROJECT_SOURCE_DIR}/src/math.hpp
${PROJECT_SOURCE_DIR}/src/point.hpp
${PROJECT_SOURCE_DIR}/src/segment.hpp
${PROJECT_SOURCE_DIR}/src/swcio.hpp
${PROJECT_SOURCE_DIR}/src/tree.hpp
)
set(TEST_SOURCES
# unit tests
test_algorithms.cpp
......@@ -47,7 +37,7 @@ set(TEST_SOURCES
)
add_definitions("-DDATADIR=\"${CMAKE_SOURCE_DIR}/data\"")
add_executable(test.exe ${TEST_SOURCES} ${HEADERS})
add_executable(test.exe ${TEST_SOURCES})
set(TARGETS test.exe)
......
......@@ -184,6 +184,16 @@ TEST(range, sentinel) {
EXPECT_EQ(0u, empty_cstr_range.size());
}
TEST(range, strictify) {
const char *cstr = "hello world";
auto cstr_range = util::make_range(cstr, null_terminated);
auto ptr_range = util::strict_view(cstr_range);
EXPECT_TRUE((std::is_same<decltype(ptr_range), util::range<const char *>>::value));
EXPECT_EQ(cstr, ptr_range.left);
EXPECT_EQ(cstr+11, ptr_range.right);
}
template <typename V>
class counter_range: public ::testing::Test {};
......@@ -290,12 +300,15 @@ TEST(range, sort) {
auto cstr_range = util::make_range(std::begin(cstr), null_terminated);
// Alas, no forward_iterator sort yet, so make a strict (non-sentinel)
// range to sort on below
// simple sort
util::sort(cstr_range);
util::sort(util::strict_view(cstr_range));
EXPECT_EQ(std::string("dhowy"), cstr);
// reverse sort by transform c to -c
util::sort_by(cstr_range, [](char c) { return -c; });
util::sort_by(util::strict_view(cstr_range), [](char c) { return -c; });
EXPECT_EQ(std::string("ywohd"), cstr);
}
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment