Info
-
Did you know that C++23 added
ranges::to
(conversion from ranges to containers)?
Example
int main() {
auto v = ranges::views::ints | ranges::views::take(2);
auto o = v | ranges::to<std::vector>();
assert(std::size(o) == 2 and o[0] == 0 and o[1] == 1);
}
Puzzle
- Can you implement
to_vector
which converts given range into vector using ranges/stl?
namespace test::ranges {
[[nodiscard]] constexpr auto to_vector(std::ranges::range auto range) {
// TODO
}
} // test::ranges
namespace test::stl {
[[nodiscard]] constexpr auto to_vector(::std::ranges::range auto range) {
// TODO
}
} // test::stl
int main() {
using boost::ut::operator ""_test;
using boost::ut::expect;
auto test = [](auto to_vector) {
"ranges.to"_test = [=] {
"view"_test = [=] {
const auto view = ranges::views::ints | ranges::views::take(3);
expect(std::vector{0, 1, 2} == to_vector(view));
};
"list"_test = [=] {
const std::list l{1, 2, 3};
expect(std::vector{1, 2, 3} == to_vector(l));
};
"string"_test = [=] {
const std::string s = "str";
expect(std::vector{'s', 't', 'r'} == to_vector(s));
};
};
};
test([](auto... ts) { return test::ranges::to_vector(ts...); });
test([](auto... ts) { return test::stl::to_vector(ts...); });
}
Solutions
namespace test::ranges {
[[nodiscard]] constexpr auto to_vector(std::ranges::range auto range) {
return range | ::ranges::to<std::vector>();
}
} // namespace test::ranges
namespace test::stl {
[[nodiscard]] constexpr auto to_vector(std::ranges::range auto range) {
using value_type =
std::remove_cvref_t<decltype(*std::ranges::begin(range))>;
std::vector<value_type> output{};
if constexpr (requires { std::size(range); }) {
output.reserve(std::size(range));
}
std::ranges::copy(std::ranges::begin(range), std::ranges::end(range),
std::back_inserter(output));
return output;
}
} // namespace test::stl
namespace test::ranges {
[[nodiscard]] constexpr auto to_vector(std::ranges::range auto range) {
auto cv = ::ranges::views::common(range);
return std::vector(cv.begin(), cv.end());
}
} // namespace test::ranges
namespace test::stl {
[[nodiscard]] constexpr auto to_vector(::std::ranges::range auto range) {
auto cv = ::std::ranges::views::common(std::move(range));
return std::vector(cv.begin(), cv.end());
}
} // namespace test::stl
namespace test::ranges {
[[nodiscard]] constexpr auto to_vector(std::ranges::range auto range) {
return range | ::ranges::to<std::vector>();
}
} // namespace test::ranges
namespace test::stl {
[[nodiscard]] constexpr auto to_vector(std::ranges::range auto range) {
std::vector<std::ranges::range_value_t<decltype(range)>> ret;
if constexpr(std::ranges::sized_range<decltype(range)>) {
ret.reserve(std::ranges::size(range));
}
std::ranges::copy(range, std::back_inserter(ret));
return ret;
}
} // namespace test::stl
namespace test::ranges {
[[nodiscard]] constexpr auto to_vector(std::ranges::range auto range) {
// TODO
}
} // test::ranges
namespace test::stl {
[[nodiscard]] constexpr auto to_vector(::std::ranges::range auto range) {
// TODO
}
} // test::stl
int main() {
using boost::ut::operator ""_test;
using boost::ut::expect;
auto test = [](auto to_vector) {
"ranges.to"_test = [=] {
"view"_test = [=] {
const auto view = ranges::views::ints | ranges::views::take(3);
expect(std::vector{0, 1, 2} == to_vector(view));
};
"list"_test = [=] {
const std::list l{1, 2, 3};
expect(std::vector{1, 2, 3} == to_vector(l));
};
"string"_test = [=] {
const std::string s = "str";
expect(std::vector{'s', 't', 'r'} == to_vector(s));
};
};
};
test([](auto... ts) { return test::ranges::to_vector(ts...); });
test([](auto... ts) { return test::stl::to_vector(ts...); });
}
namespace test::ranges {
[[nodiscard]] constexpr auto to_vector(std::ranges::range auto range) {
return ::ranges::to<std::vector>(std::move(range));
}
} // test::ranges
namespace test::stl {
[[nodiscard]] constexpr auto to_vector(::std::ranges::range auto range) {
auto v = std::vector<std::ranges::range_value_t<decltype(range)>>{};
v.reserve(std::ranges::distance(std::ranges::begin(range), std::ranges::end(range)));
std::ranges::copy(std::ranges::begin(range), std::ranges::end(range), std::back_inserter(v));
return v;
}
} // test::stl
namespace test::ranges {
[[nodiscard]] constexpr auto to_vector(std::ranges::range auto range) {
return ::ranges::to<std::vector>(range);
}
} // test::ranges
namespace test::stl {
[[nodiscard]] constexpr auto to_vector(::std::ranges::range auto range) {
std::vector<std::ranges::range_value_t<decltype(range)>> output{};
output.reserve(std::ranges::size(range));
std::ranges::copy(range.begin(), range.end(), std::back_inserter(output));
return output;
}
} // test::stl
namespace test::ranges {
[[nodiscard]] constexpr auto to_vector(std::ranges::range auto range) {
return std::move(range) | ::ranges::to<std::vector>();
}
} // test::ranges
namespace test::stl {
[[nodiscard]] constexpr auto to_vector(::std::ranges::range auto range) {
auto vec = std::vector<std::ranges::range_value_t<decltype(range)>>{};
vec.reserve(std::ranges::size(range));
std::ranges::move(range, std::back_inserter(vec));
return vec;
}
} // test::stl
namespace test::ranges {
[[nodiscard]] constexpr auto to_vector(std::ranges::range auto range) {
return range | ::ranges::to<std::vector>();
}
} // test::ranges
namespace test::stl {
[[nodiscard]] constexpr auto to_vector(::std::ranges::range auto range) {
return range | ::ranges::to<std::vector>();
}
} // test::stl
namespace test::ranges {
[[nodiscard]] constexpr auto to_vector(std::ranges::range auto range) {
return range | ::ranges::to<std::vector>();
}
} // test::ranges
namespace test::stl {
[[nodiscard]] constexpr auto to_vector(::std::ranges::range auto range) {
std::vector<std::ranges::range_value_t<decltype(range)>> vec{};
vec.reserve(std::ranges::size(range));
std::ranges::copy(std::ranges::begin(range), std::ranges::end(range), std::back_inserter(vec));
return vec;
}
} // test::stl
namespace test::ranges {
[[nodiscard]] constexpr auto to_vector(std::ranges::range auto range) {
return range | ::ranges::to<std::vector>();
}
} // test::ranges
namespace test::stl {
template <::std::ranges::range R>
[[nodiscard]] constexpr auto to_vector(R range) {
auto vec = std::vector<std::ranges::range_value_t<R>>{};
std::ranges::copy(range, std::back_inserter(vec));
return vec;
}
} // test::stl
namespace test::ranges {
[[nodiscard]] constexpr auto to_vector(std::ranges::range auto range) {
std::vector<std::ranges::range_value_t<decltype(range)>> v;
std::ranges::copy(range, std::back_inserter(v));
return v;
}
} // test::ranges
namespace test::stl {
[[nodiscard]] constexpr auto to_vector(::std::ranges::range auto range) {
using iT = std::ranges::iterator_t<decltype(range)>;
using T = std::ranges::range_value_t<decltype(range)>;
std::vector<T> v;
for(iT iE = range.begin(); iE !=range.end(); iE++)
v.push_back(*iE);
return v;
}
} // test::stl
namespace test::ranges {
[[nodiscard]] constexpr auto to_vector(std::ranges::range auto range) {
return ::ranges::to<std::vector>(range);
}
} // test::ranges
namespace test::stl {
[[nodiscard]] constexpr auto to_vector(::std::ranges::range auto range) {
std::vector<std::ranges::range_value_t<decltype(range)>> v;
if constexpr(std::ranges::sized_range<decltype(range)>) {
v.reserve(std::ranges::size(range));
}
std::ranges::copy(range, std::back_inserter(v));
return v;
}
} // test::stl