I am implementing a function that takes a range with values of type std::byte
and
returns a view on bits of given range. I've implemented two specializations: for random_access
range and not random_access
:
#include <iostream>
#include <ranges>
#include <vector>
#include <iostream>
#include <list>
#include <algorithm>
using std::views::iota;
using std::views::join;
using std::views::transform;
using std::views::reverse;
template <std::ranges::range Rng>
requires std::ranges::random_access_range<Rng> &&
std::is_same_v<std::ranges::range_value_t<Rng>, std::byte>
auto to_bits(const Rng &rng) {
return iota(std::size_t{0}, rng.size() * 8) |
transform([&rng](std::size_t i) {
const std::size_t byteIdx = i / 8;
const std::size_t bitIdx = 7 - i % 8;
return (rng[byteIdx] >> bitIdx) & std::byte{1};
});
}
template <std::ranges::range Rng>
requires(!std::ranges::random_access_range<Rng>) &&
std::is_same_v<std::ranges::range_value_t<Rng>, std::byte>
auto to_bits(const Rng &rng) {
return rng | transform([](const std::byte &b) {
return iota(0, 8)
| reverse
| transform([&b](auto i) -> std::byte {
return (b >> i) & std::byte{1};
});
}) |
join;
}
The second is for not random_access
ranges. The usage of the function is supposed to be the following:
int main() {
auto v = std::vector{std::byte{0}, std::byte{42}};
auto vBits = to_bits(v);
static_assert(std::ranges::random_access_range<decltype(vBits)>);
static_assert(std::ranges::sized_range<decltype(vBits)>);
static_assert(std::is_same_v<std::ranges::range_value_t<decltype(vBits)>, std::byte>);
auto l = std::list{std::byte{0}, std::byte{42}};
auto lBits = to_bits(l);
static_assert(std::ranges::input_range<decltype(lBits)>);
// static_assert(std::ranges::sized_range<decltype(lBits)>); // Why not be sized?
static_assert(std::is_same_v<std::ranges::range_value_t<decltype(lBits)>, std::byte>);
std::cout << (std::ranges::equal(vBits, lBits) ? "Equal." : "Not equal.") << std::endl;
return 0;
}
The problem with second variant is the following: if a given
range is sized we can say the size of a view, but join
is not sized.
How to make view be sized manually? Is it a good idea to implement a view with manually
given size and that requires an argument view with no size?