Skip to content

Commit 18f2a5c

Browse files
Updated readme and synopsis to reflect wording in P3411R2
1 parent 115731b commit 18f2a5c

File tree

5 files changed

+127
-48
lines changed

5 files changed

+127
-48
lines changed

.markdownlint.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ MD033: false
99
# Update the comment in .clang-format if we no-longer tie these two column limits.
1010
MD013:
1111
line_length: 119
12+
code_blocks: false

README.md

Lines changed: 112 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,26 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
44

55
# beman.any_view: A generalized type-erased view with customizable properties
66

7-
![Library Status](https://github.com/bemanproject/beman/blob/c6997986557ec6dda98acbdf502082cdf7335526/images/badges/beman_badge-beman_library_under_development.svg)
7+
![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg)
88
![Continuous Integration Tests](https://github.com/bemanproject/any_view/actions/workflows/ci_tests.yml/badge.svg)
99
![Lint Check (pre-commit)](https://github.com/bemanproject/any_view/actions/workflows/pre-commit.yml/badge.svg)
1010

11-
**Implements**: `std::ranges::any_view` proposed in [any_view (P3411R2)](https://huixie90.github.io/cpp_papers/generated/any_view).
11+
**Implements**: `std::ranges::any_view` proposed in [any_view (P3411R2)](https://wg21.link/p3411r2).
1212

1313
**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#under-development-and-not-yet-ready-for-production-use)
1414

15+
**Featured**: [C++Now 2025](https://schedule.cppnow.org/session/2025/a-view-for-any-occasion)
16+
17+
## Motivation
18+
19+
`any_view` equips library APIs with the ability to declare function parameters and return types that are views, while
20+
de-coupling the interface from an implementation that can fully leverage the power of C++20 ranges. By using
21+
type-erased views, the library can be compiled separately.
22+
23+
As a return type, `any_view` grants a library author the freedom to change how the function is implemented to return
24+
the view without modifying its interface. As a parameter type, it allows users to call the library function with any
25+
range as an argument that can be consumed directly, rather than copying it into some bespoke, library-specific type.
26+
1527
## Usage
1628

1729
```cpp
@@ -64,10 +76,11 @@ For CMake based projects, you can include it as a dependency using the `FetchCon
6476
include(FetchContent)
6577
6678
FetchContent_Declare(
67-
beman.any_view
68-
GIT_REPOSITORY https://github.com/bemanproject/any_view.git
69-
GIT_TAG main
70-
EXCLUDE_FROM_ALL)
79+
beman.any_view
80+
GIT_REPOSITORY https://github.com/bemanproject/any_view.git
81+
GIT_TAG main
82+
EXCLUDE_FROM_ALL
83+
)
7184
FetchContent_MakeAvailable(beman.any_view)
7285
```
7386

@@ -88,6 +101,7 @@ target_link_libraries(yourlib PUBLIC beman::any_view)
88101
```cpp
89102
namespace beman::any_view {
90103

104+
// [range.any]
91105
enum class any_view_options {
92106
input = 0b00000001,
93107
forward = 0b00000011,
@@ -99,19 +113,21 @@ enum class any_view_options {
99113
copyable = 0b10000000,
100114
};
101115

102-
constexpr any_view_options operator|(any_view_options l, any_view_options r) noexcept;
103-
constexpr any_view_options operator&(any_view_options l, any_view_options r) noexcept;
104-
constexpr any_view_options operator^(any_view_options l, any_view_options r) noexcept;
116+
constexpr any_view_options operator|(any_view_options, any_view_options) noexcept;
117+
constexpr any_view_options operator&(any_view_options, any_view_options) noexcept;
105118

106-
constexpr any_view_options operator~(any_view_options o) noexcept;
119+
template <class T>
120+
struct /*rvalue-ref*/ {
121+
using type = T;
122+
};
107123

108-
constexpr any_view_options& operator|=(any_view_options& l, any_view_options r) noexcept;
109-
constexpr any_view_options& operator&=(any_view_options& l, any_view_options r) noexcept;
110-
constexpr any_view_options& operator^=(any_view_options& l, any_view_options r) noexcept;
124+
template <class T>
125+
struct /*rvalue-ref*/<T&> {
126+
using type = T&&;
127+
};
111128

112-
template <class T> struct /*as-rvalue*/ { using type = T; };
113-
template <class T> struct /*as-rvalue*/<T&> { using type = T&&; };
114-
template <class T> using /*as-rvalue-t*/ = /*as-rvalue*/<T>::type;
129+
template <class T>
130+
using /*rvalue-ref-t*/ = /*rvalue-ref*/<T>::type;
115131

116132
template <class RangeT, class AnyViewT>
117133
concept ext_any_compatible_viewable_range = /* see description */;
@@ -125,30 +141,29 @@ class any_view : public std::ranges::view_interface<any_view<ElementT, OptsV, Re
125141
class iterator; // exposition-only
126142
class sentinel; // exposition-only
127143

128-
using size_type = std::make_unsigned_t<DiffT>; // exposition-only
129-
130144
public:
145+
// [range.any.ctor]
131146
template <class RangeT>
132-
requires(not std::same_as<std::remove_cvref_t<RangeT>, any_view> and
133-
ext_any_compatible_viewable_range<RangeT, any_view>)
134147
constexpr any_view(RangeT&& range);
135-
136-
constexpr any_view(const any_view&)
137-
requires(bool(OptsV & any_view_options::copyable));
138-
148+
constexpr any_view(const any_view&);
139149
constexpr any_view(any_view&&) noexcept;
140150

141-
constexpr any_view& operator=(const any_view&)
142-
requires(bool(OptsV & any_view_options::copyable));
143-
151+
constexpr any_view& operator=(const any_view&);
144152
constexpr any_view& operator=(any_view&&) noexcept;
145153

154+
constexpr ~any_view();
155+
156+
// [range.any.access]
146157
constexpr iterator begin();
147158

148159
constexpr sentinel end();
149160

150-
constexpr size_type size() const
151-
requires(bool(OptsV & any_view_options::sized));
161+
constexpr std::make_unsigned_t<DiffT> size() const;
162+
163+
// [range.any.swap]
164+
constexpr void swap(any_view&) noexcept;
165+
166+
constexpr friend void swap(any_view&, any_view&) noexcept;
152167
};
153168

154169
} // namespace beman::any_view
@@ -267,6 +282,74 @@ Total Test time (real) = 0.15 sec
267282

268283
</details>
269284

285+
## Performance
286+
287+
Various benchmarks are available to build and run using the CMake target `beman.any_view.benchmarks`.
288+
289+
<details>
290+
<summary>Example output comparing <code>reserved</code> to <code>fused</code> for <code>beman.any_view.benchmarks.all</code></summary>
291+
292+
```text
293+
+ cmake --build build --config Release --target beman.any_view.benchmarks.all
294+
[27/27] Linking CXX executable tests/beman/any_view/beman.any_view.benchmarks.all
295+
+ build/_deps/benchmark-src/tools/compare.py benchmarksfiltered build/tests/beman/any_view/beman.any_view.benchmarks.all reserved build/tests/beman/any_view/beman.any_view.benchmarks.all fused
296+
RUNNING: build/tests/beman/any_view/beman.any_view.benchmarks.all --benchmark_filter=reserved
297+
Run on (32 X 2419.2 MHz CPU s)
298+
CPU Caches:
299+
L1 Data 48 KiB (x16)
300+
L1 Instruction 32 KiB (x16)
301+
L2 Unified 2048 KiB (x16)
302+
L3 Unified 36864 KiB (x1)
303+
Load Average: 0.25, 0.17, 0.11
304+
-----------------------------------------------------------------
305+
Benchmark Time CPU Iterations
306+
-----------------------------------------------------------------
307+
BM_all_reserved/1024 1783 ns 1783 ns 389936
308+
BM_all_reserved/2048 3839 ns 3839 ns 191729
309+
BM_all_reserved/4096 7067 ns 7067 ns 89826
310+
BM_all_reserved/8192 14756 ns 14756 ns 48245
311+
BM_all_reserved/16384 30317 ns 30317 ns 23191
312+
BM_all_reserved/32768 73651 ns 73650 ns 9626
313+
BM_all_reserved/65536 215342 ns 215341 ns 3413
314+
BM_all_reserved/131072 424794 ns 424793 ns 1654
315+
BM_all_reserved/262144 887833 ns 887828 ns 789
316+
RUNNING: build/tests/beman/any_view/beman.any_view.benchmarks.all --benchmark_filter=fused
317+
Run on (32 X 2419.2 MHz CPU s)
318+
CPU Caches:
319+
L1 Data 48 KiB (x16)
320+
L1 Instruction 32 KiB (x16)
321+
L2 Unified 2048 KiB (x16)
322+
L3 Unified 36864 KiB (x1)
323+
Load Average: 0.31, 0.19, 0.11
324+
--------------------------------------------------------------
325+
Benchmark Time CPU Iterations
326+
--------------------------------------------------------------
327+
BM_all_fused/1024 1660 ns 1660 ns 437469
328+
BM_all_fused/2048 3219 ns 3219 ns 210096
329+
BM_all_fused/4096 7100 ns 7100 ns 100823
330+
BM_all_fused/8192 15088 ns 15088 ns 45117
331+
BM_all_fused/16384 33719 ns 33719 ns 21827
332+
BM_all_fused/32768 72098 ns 72097 ns 9582
333+
BM_all_fused/65536 150699 ns 150698 ns 4629
334+
BM_all_fused/131072 316431 ns 316430 ns 2234
335+
BM_all_fused/262144 583499 ns 583500 ns 1091
336+
Comparing reserved (from build/tests/beman/any_view/beman.any_view.benchmarks.all) to fused (from build/tests/beman/any_view/beman.any_view.benchmarks.all)
337+
Benchmark Time CPU Time Old Time New CPU Old CPU New
338+
---------------------------------------------------------------------------------------------------------------------------------
339+
BM_all_[reserved vs. fused]/1024 -0.0689 -0.0689 1783 1660 1783 1660
340+
BM_all_[reserved vs. fused]/2048 -0.1615 -0.1615 3839 3219 3839 3219
341+
BM_all_[reserved vs. fused]/4096 +0.0047 +0.0047 7067 7100 7067 7100
342+
BM_all_[reserved vs. fused]/8192 +0.0225 +0.0225 14756 15088 14756 15088
343+
BM_all_[reserved vs. fused]/16384 +0.1122 +0.1122 30317 33719 30317 33719
344+
BM_all_[reserved vs. fused]/32768 -0.0211 -0.0211 73651 72098 73650 72097
345+
BM_all_[reserved vs. fused]/65536 -0.3002 -0.3002 215342 150699 215341 150698
346+
BM_all_[reserved vs. fused]/131072 -0.2551 -0.2551 424794 316431 424793 316430
347+
BM_all_[reserved vs. fused]/262144 -0.3428 -0.3428 887833 583499 887828 583500
348+
OVERALL_GEOMEAN -0.1255 -0.1255
349+
```
350+
351+
</details>
352+
270353
## Contributing
271354

272355
Please do! Issues and pull requests are appreciated.

include/beman/any_view/any_view.hpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ namespace beman::any_view {
1010
template <class ElementT,
1111
any_view_options OptsV = any_view_options::input,
1212
class RefT = ElementT&,
13-
class RValueRefT = detail::as_rvalue_t<RefT>,
13+
class RValueRefT = detail::rvalue_ref_t<RefT>,
1414
class DiffT = std::ptrdiff_t>
1515
class any_view : public std::ranges::view_interface<any_view<ElementT, OptsV, RefT, RValueRefT, DiffT>> {
16-
static_assert((OptsV & any_view_options::input) == any_view_options::input, "any_view must model input_range");
16+
static_assert(bool(OptsV & any_view_options::input), "any_view must model input_range");
1717

1818
using iterator_concept = decltype(detail::get_iter_concept<OptsV>());
1919
using iterator = detail::any_iterator<iterator_concept, ElementT, RefT, RValueRefT, DiffT>;
@@ -31,6 +31,7 @@ class any_view : public std::ranges::view_interface<any_view<ElementT, OptsV, Re
3131
}
3232

3333
public:
34+
// [range.any.ctor]
3435
template <class RangeT>
3536
requires(not std::same_as<std::remove_cvref_t<RangeT>, any_view> and
3637
ext_any_compatible_viewable_range<RangeT, any_view>)
@@ -49,6 +50,9 @@ class any_view : public std::ranges::view_interface<any_view<ElementT, OptsV, Re
4950

5051
constexpr any_view& operator=(any_view&&) noexcept = default;
5152

53+
constexpr ~any_view() = default;
54+
55+
// [range.any.access]
5256
[[nodiscard]] constexpr iterator begin() { return view_ptr->begin(); }
5357

5458
[[nodiscard]] constexpr sentinel end() { return std::default_sentinel; }
@@ -58,6 +62,11 @@ class any_view : public std::ranges::view_interface<any_view<ElementT, OptsV, Re
5862
{
5963
return view_ptr->size();
6064
}
65+
66+
// [range.any.swap]
67+
constexpr void swap(any_view& other) noexcept { std::swap(view_ptr, other.view_ptr); }
68+
69+
constexpr friend void swap(any_view& lhs, any_view& rhs) noexcept { return lhs.swap(rhs); }
6170
};
6271

6372
} // namespace beman::any_view

include/beman/any_view/any_view_options.hpp

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,6 @@ enum class any_view_options {
2424
return any_view_options(static_cast<int>(l) & static_cast<int>(r));
2525
}
2626

27-
[[nodiscard]] constexpr any_view_options operator^(any_view_options l, any_view_options r) noexcept {
28-
return any_view_options(static_cast<int>(l) ^ static_cast<int>(r));
29-
}
30-
31-
[[nodiscard]] constexpr any_view_options operator~(any_view_options o) noexcept {
32-
return any_view_options(~static_cast<int>(o));
33-
}
34-
35-
constexpr any_view_options& operator|=(any_view_options& l, any_view_options r) noexcept { return l = l | r; }
36-
37-
constexpr any_view_options& operator&=(any_view_options& l, any_view_options r) noexcept { return l = l & r; }
38-
39-
constexpr any_view_options& operator^=(any_view_options& l, any_view_options r) noexcept { return l = l ^ r; }
40-
4127
} // namespace beman::any_view
4228

4329
#endif // BEMAN_ANY_VIEW_ANY_VIEW_OPTIONS_HPP

include/beman/any_view/detail/type_traits.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@
1010
namespace beman::any_view::detail {
1111

1212
template <class T>
13-
struct as_rvalue : std::type_identity<T> {};
13+
struct rvalue_ref : std::type_identity<T> {};
1414

1515
template <class T>
16-
struct as_rvalue<T&> : std::type_identity<T&&> {};
16+
struct rvalue_ref<T&> : std::type_identity<T&&> {};
1717

1818
template <class T>
19-
using as_rvalue_t = as_rvalue<T>::type;
19+
using rvalue_ref_t = rvalue_ref<T>::type;
2020

2121
template <any_view_options OptionsV>
2222
[[nodiscard]] consteval auto get_iter_concept() {

0 commit comments

Comments
 (0)