Implements: Range adaptor and iterators proposed in Adaptors For Closed Ranges (P4211R0).
Difference from the paper:
- Implemented
reserve_hintare hidden behind a feature-test macro.
Status: Under development and not yet ready for production use.
beman.closed_view is licensed under the Apache License v2.0 with LLVM Exceptions.
The proposal will add several facilities that accommodates (both side) closed ranges and adapts them into half-open ranges that every other C++ range facilities expects. Specifically, the proposal introduced the following additions:
views::closedandranges::closed_view: Adapting a pair of iterators and sentinels representing closed ranges into half-open ones.views::lazy_countedandstd::lazy_counted_iterator: A version ofcounted_iteratorthat skips the last increment of underlying iterators.views::lazy_takeandranges::lazy_take_view: A version oftake_viewthat utilize lazy version ofcounted_iteratorto prevent overshooting the underlying range.views::closed_iota(a, b)that represents the range[a, b](closed version ofviews::iota). Equivalent toviews::closed+views::iota(a, b).
#include <limits>
#include <sstream>
#include <print>
#include <ranges>
#include <vector>
#include <beman/closed_view/closed.hpp>
namespace views = std::views;
namespace exe = beman::closed_view;
// Example given in the paper for closed views. (Needs C++23)
int main()
{
std::println("{}", views::iota(0, 5)); // [0, 1, 2, 3, 4]
std::println("{}", exe::closed_iota(0, 5)); // [0, 1, 2, 3, 4, 5]
int max = std::numeric_limits<int>::max();
std::println("{}", views::iota(max - 20, max)); // fine but not including max
std::println("{}", views::iota(max - 20, -max - 1)); // UB
std::println("{}", exe::closed_iota(max - 20, max)); // ok, includes max
std::vector vec{1, 2, 3, 4, 5};
std::println("{}", exe::as_closed(vec.begin() + 2, vec.begin() + 4)); // [3, 4, 5]
// A range with 11 elements but calculating 12th element overflows
auto weird = views::iota(0) | views::filter([](auto i) { return i < 11; });
std::println("{}", weird); // UB
std::println("{}", weird | exe::lazy_take(11)); // fine, 0-10
std::println("{}", weird | views::take(10) | exe::as_closed); // also fine, 0-10
auto iss = std::istringstream("0 1 2");
auto weird2 = views::istream<int>(iss) | views::take(1);
std::println("{}", weird2); // fine, [0]
auto i = 0; iss >> i;
// now i = 2 (!)
auto iss2 = std::istringstream("0 1 2");
auto ok2 = views::istream<int>(iss) | exe::lazy_take(1);
std::println("{}", ok2); // fine, [0]
auto i2 = 0; iss2 >> i2;
// now i2 = 1 as expected
return 0;
}Full runnable examples can be found in examples/.
This project requires at least the following to build:
- A C++ compiler that conforms to the C++20 standard or greater
- CMake 3.30 or later
- (Test Only) GoogleTest
You can disable building tests by setting CMake option BEMAN_CLOSED_VIEW_BUILD_TESTS to
OFF when configuring the project.
| Compiler | Version | C++ Standards | Standard Library |
|---|---|---|---|
| GCC | 16-13 | C++26-C++20 | libstdc++ |
| GCC | 12-11 | C++23, C++20 | libstdc++ |
| Clang | 20-19 | C++26-C++20 | libstdc++, libc++ |
| Clang | 18-17 | C++26-C++20 | libc++ |
| Clang | 18-17 | C++20 | libstdc++ |
| AppleClang | latest | C++26-C++20 | libc++ |
| MSVC | latest | C++23 | MSVC STL |
See the Contributing Guidelines.
You can build closed_view using a CMake workflow preset:
cmake --workflow --preset gcc-releaseTo list available workflow presets, you can invoke:
cmake --list-presets=workflowFor details on building beman.closed_view without using a CMake preset, refer to the Contributing Guidelines.
The preferred way to install closed_view is via vcpkg. To do so, after installing vcpkg
itself, you need to add support for the Beman project's vcpkg
registry by configuring a
vcpkg-configuration.json file (which closed_view provides).
Then, simply run vcpkg install beman-closed-view.
To install beman.closed_view globally after building with the gcc-release preset, you can
run:
sudo cmake --install build/gcc-releaseAlternatively, to install to a prefix, for example /opt/beman, you can run:
sudo cmake --install build/gcc-release --prefix /opt/bemanThis will generate the following directory structure:
/opt/beman
├── include
│ └── beman
│ └── closed_view
│ ├── closed.hpp
│ └── ...
└── lib
└── cmake
└── beman.closed_view
├── beman.closed_view-config-version.cmake
├── beman.closed_view-config.cmake
└── beman.closed_view-targets.cmakeIf you installed beman.closed_view to a prefix, you can specify that prefix to your CMake
project using CMAKE_PREFIX_PATH; for example, -DCMAKE_PREFIX_PATH=/opt/beman.
You need to bring in the beman.closed_view package to define the beman::closed_view CMake
target:
find_package(beman.closed_view REQUIRED)You will then need to add beman::closed_view to the link libraries of any libraries or
executables that include beman.closed_view headers.
target_link_libraries(yourlib PUBLIC beman::closed_view)To use beman.closed_view in your C++ project,
include an appropriate beman.closed_view header from your source code.
#include <beman/closed_view/closed.hpp>Note
beman.closed_view headers are to be included with the beman/closed_view/ prefix.
Altering include search paths to spell the include target another way (e.g.
#include <closed.hpp>) is unsupported.