Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
95346e3
Rename distance_t -> int_t
tcbrindle May 13, 2025
8ee1431
Add iterable and reverse_iterable concepts
tcbrindle May 13, 2025
4c98b77
Temporarily rename for_each_while on sequences
tcbrindle May 13, 2025
e5102e0
Modify many algorithms to work on iterables
tcbrindle May 15, 2025
d42b540
Add find_element tests
tcbrindle May 15, 2025
da005da
Update ranges::to to use iterables
tcbrindle May 16, 2025
6b9070c
Re-enable deduction guide for defer_t
tcbrindle May 16, 2025
34559d9
Add missing header
tcbrindle May 16, 2025
536bd7a
At iterable impl to filter
tcbrindle May 17, 2025
a986c28
Add iterable protocol to reverse_adaptor
tcbrindle May 18, 2025
905a42b
Add iterable conformance to map
tcbrindle May 19, 2025
553bd3e
Add iterable conformance to take()
tcbrindle May 19, 2025
9199e78
Add iterable protocol to take_while
tcbrindle May 19, 2025
9baef5b
Make stride() iterable
tcbrindle May 19, 2025
3033794
Make drop() implement iterable
tcbrindle May 20, 2025
c480169
Make take() and drop() reverse_iterable
tcbrindle May 20, 2025
b1d4e8d
Make drop_while() implement iterable
tcbrindle May 20, 2025
0c8971e
(Try to) fix some CI build errors
tcbrindle May 20, 2025
fd3a7c7
Fix Clang 17 compilation
tcbrindle May 21, 2025
90660ba
More Clang CTAD fixes
tcbrindle May 21, 2025
ff329a6
Implement iterable for flatten()
tcbrindle May 22, 2025
e5e1c56
Update flatten_with() for iterables
tcbrindle May 23, 2025
9c32a08
Add iterable conformance to chain()
tcbrindle May 23, 2025
c1ad734
Add a 4th(!) chunk implementation
tcbrindle May 23, 2025
692018e
Disable constexpr chain() test for older libc++
tcbrindle May 23, 2025
284bda3
Iterables for scan(), prescan() and scan_first()
tcbrindle May 23, 2025
8041677
Make map() reverse_iterable
tcbrindle May 23, 2025
382755c
Make filter_map() and filter_deref() iterable
tcbrindle May 23, 2025
23886aa
Add iterable support to mask()
tcbrindle May 23, 2025
e85e0fb
Add missing headers in tests
tcbrindle May 23, 2025
66f3233
Make read_only() iterable
tcbrindle May 23, 2025
982e3f8
Make zip() iterable
tcbrindle Jun 10, 2025
850ba93
Make zip_map() iterable
tcbrindle Jun 10, 2025
3e828d7
CMake: disable bogus GCC warning
tcbrindle Jun 10, 2025
9201a3e
Zip: don't use return type which can hard error
tcbrindle Jun 10, 2025
7f18895
Reverse: Fix incorrect decltype constraint
tcbrindle Jun 10, 2025
6759d20
Use array rather than init_list in top10 examples
tcbrindle Jun 10, 2025
16311ff
Zip: try to placate MSVC
tcbrindle Jun 10, 2025
75149b6
Try again to make MSVC happy
tcbrindle Jun 10, 2025
cfb925d
Rename chunk<single_pass_seq>::value_type
tcbrindle Jun 10, 2025
56bf6ae
Add missing #include for std::unreachable
tcbrindle Jun 10, 2025
f5dc6fe
Fix clang complaints about make_single_header
tcbrindle Jun 10, 2025
4454e01
More MSVC whack-a-mole
tcbrindle Jun 10, 2025
1fff11a
Add internal iteration for adjacent_filter
tcbrindle Jun 17, 2025
87c23f6
Make flux::generator an iterable (only)
tcbrindle Aug 13, 2025
8ae756d
element_type for generator<T> is T&&
tcbrindle Aug 13, 2025
e4d1199
Make ref() and mut_ref() accept iterables
tcbrindle Aug 13, 2025
a0d34df
Make std::istreambufs iterable
tcbrindle Aug 13, 2025
0f46623
Use iterable_element_t and iterable_value_t...
tcbrindle Aug 13, 2025
be0dc9d
Fix generator errors on MSVC
tcbrindle Aug 13, 2025
3a1a09b
Make from_istream iterable only
tcbrindle Aug 13, 2025
531e40c
Fix broken examples
tcbrindle Aug 14, 2025
f737564
Make getlines() iterable only
tcbrindle Aug 14, 2025
2259b11
Make iterables work with range-for
tcbrindle Aug 14, 2025
2e6719f
Make unfold() iterable-only
tcbrindle Aug 14, 2025
c9f3fa2
Remove from_range() and from_crange()
tcbrindle Aug 14, 2025
391ab0c
Require mulitpass for the various set adaptors
tcbrindle Aug 14, 2025
2fbea60
Remove flux::array_ptr
tcbrindle Aug 14, 2025
e63d308
Update flux::iota for new concepts
tcbrindle Aug 14, 2025
069050b
Make infinite repeat() iterable-only
tcbrindle Aug 15, 2025
4fb7903
Make infinite repeat reverse_iterable
tcbrindle Aug 15, 2025
5273f43
Disable GCC 15 module builds for now
tcbrindle Oct 22, 2025
21f2147
Fix Codecov CI build failure
tcbrindle Oct 22, 2025
284377f
Don't try to count coverage for unreachable()
tcbrindle Oct 22, 2025
16dfcb0
Move bitset sequence impl to default_impls.hpp
tcbrindle Oct 24, 2025
c4a5513
Rename sequence source dir to factory
tcbrindle Oct 24, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ IndentPPDirectives: AfterHash
InsertBraces: true
NamespaceIndentation: None
PackConstructorInitializers: CurrentLine
SpaceBeforeCpp11BracedList: false
SortIncludes: Never
TabWidth: 4
2 changes: 2 additions & 0 deletions .github/workflows/linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ jobs:
test_with: Module
- compiler: GCC-14
test_with: Module
- compiler: GCC-15
test_with: Module
- compiler: Clang-17
test_with: Module

Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ target_compile_options(flux-internal INTERFACE
-ftemplate-backtrace-limit=0
>

$<$<CXX_COMPILER_ID:GNU>: -fconcepts-diagnostics-depth=2>
$<$<CXX_COMPILER_ID:GNU>: -fconcepts-diagnostics-depth=2 -Wno-missing-field-initializers>

$<$<CXX_COMPILER_ID:Clang,AppleClang>: -fconstexpr-backtrace-limit=0>

Expand Down
18 changes: 10 additions & 8 deletions benchmark/multidimensional_memset_benchmark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,21 @@ namespace an = ankerl::nanobench;
// Kernels are placed in a separate translation unit to prevent compilers from
// optimizing them based on the input that we'll be giving them and to make it
// easier to study their compiled assembly.
extern void memset_2d_reference(double* A, flux::distance_t N, flux::distance_t M);
extern void memset_2d_std_cartesian_product_iota(double* A, flux::distance_t N, flux::distance_t M);
extern void memset_2d_flux_cartesian_product_iota(double* A, flux::distance_t N, flux::distance_t M);
extern void memset_diagonal_2d_reference(double* A, flux::distance_t N, flux::distance_t M);
extern void memset_diagonal_2d_std_cartesian_product_iota_filter(double* A, flux::distance_t N, flux::distance_t M);
extern void memset_diagonal_2d_flux_cartesian_product_iota_filter(double* A, flux::distance_t N, flux::distance_t M);
extern void memset_2d_reference(double* A, flux::int_t N, flux::int_t M);
extern void memset_2d_std_cartesian_product_iota(double* A, flux::int_t N, flux::int_t M);
extern void memset_2d_flux_cartesian_product_iota(double* A, flux::int_t N, flux::int_t M);
extern void memset_diagonal_2d_reference(double* A, flux::int_t N, flux::int_t M);
extern void memset_diagonal_2d_std_cartesian_product_iota_filter(double* A, flux::int_t N,
flux::int_t M);
extern void memset_diagonal_2d_flux_cartesian_product_iota_filter(double* A, flux::int_t N,
flux::int_t M);

int main(int argc, char** argv)
{
int const n_iters = argc > 1 ? std::atoi(argv[1]) : 40;

constexpr flux::distance_t N = 1024;
constexpr flux::distance_t M = 2048;
constexpr flux::int_t N = 1024;
constexpr flux::int_t M = 2048;
std::vector<double> A(N * M);

const auto run_benchmark =
Expand Down
29 changes: 17 additions & 12 deletions benchmark/multidimensional_memset_benchmark_kernels.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <flux/adaptor/cartesian_product.hpp>
#include <flux/sequence/iota.hpp>
#include <flux/factory/iota.hpp>
#include <flux/algorithm/for_each.hpp>
#include <flux/adaptor/filter.hpp>

Expand All @@ -18,14 +18,16 @@
#include <ranges>
#include <algorithm>

void memset_2d_reference(double* A, flux::distance_t N, flux::distance_t M)
void memset_2d_reference(double* A, flux::int_t N, flux::int_t M)
{
for (flux::distance_t i = 0; i != N; ++i)
for (flux::distance_t j = 0; j != M; ++j)
for (flux::int_t i = 0; i != N; ++i) {
for (flux::int_t j = 0; j != M; ++j) {
A[i * M + j] = 0.0;
}
}
}

void memset_2d_std_cartesian_product_iota(double* A, flux::distance_t N, flux::distance_t M)
void memset_2d_std_cartesian_product_iota(double* A, flux::int_t N, flux::int_t M)
{
std::ranges::for_each(
std::views::cartesian_product(std::views::iota(0, N), std::views::iota(0, M)),
Expand All @@ -34,7 +36,7 @@ void memset_2d_std_cartesian_product_iota(double* A, flux::distance_t N, flux::d
}));
}

void memset_2d_flux_cartesian_product_iota(double* A, flux::distance_t N, flux::distance_t M)
void memset_2d_flux_cartesian_product_iota(double* A, flux::int_t N, flux::int_t M)
{
flux::for_each(
flux::cartesian_product(flux::ints(0, N), flux::ints(0, M)),
Expand All @@ -43,14 +45,17 @@ void memset_2d_flux_cartesian_product_iota(double* A, flux::distance_t N, flux::
}));
}

void memset_diagonal_2d_reference(double* A, flux::distance_t N, flux::distance_t M)
void memset_diagonal_2d_reference(double* A, flux::int_t N, flux::int_t M)
{
for (flux::distance_t i = 0; i != N; ++i)
for (flux::distance_t j = 0; j != M; ++j)
if (i == j) A[i * M + j] = 0.0;
for (flux::int_t i = 0; i != N; ++i) {
for (flux::int_t j = 0; j != M; ++j) {
if (i == j)
A[i * M + j] = 0.0;
}
}
}

void memset_diagonal_2d_std_cartesian_product_iota_filter(double* A, flux::distance_t N, flux::distance_t M)
void memset_diagonal_2d_std_cartesian_product_iota_filter(double* A, flux::int_t N, flux::int_t M)
{
std::ranges::for_each(
std::views::cartesian_product(std::views::iota(0, N), std::views::iota(0, M))
Expand All @@ -60,7 +65,7 @@ void memset_diagonal_2d_std_cartesian_product_iota_filter(double* A, flux::dista
}));
}

void memset_diagonal_2d_flux_cartesian_product_iota_filter(double* A, flux::distance_t N, flux::distance_t M)
void memset_diagonal_2d_flux_cartesian_product_iota_filter(double* A, flux::int_t N, flux::int_t M)
{
flux::for_each(
flux::cartesian_product(flux::ints(0, N), flux::ints(0, M))
Expand Down
2 changes: 1 addition & 1 deletion example/docs/count.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ int main()
std::istringstream iss("1 2 3");
auto seq = flux::from_istream<int>(iss);
assert(flux::count(seq) == 3);
assert(flux::is_last(seq, flux::first(seq))); // No more elements!
assert(!iss); // No more elements!
}
18 changes: 9 additions & 9 deletions example/docs/repeat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,21 @@ using namespace std::string_view_literals;

int main()
{
// flux::repeat(val) is a random-access sequence which endlessly repeats
// flux::repeat(val) is an iterable which endlessly repeats
// the given value
auto seq = flux::repeat(3);
auto rep = flux::repeat(3);

auto cursor = flux::first(seq);
assert(flux::read_at(seq, cursor) == 3);
// fast-forward the cursor a lot...
cursor = flux::next(seq, cursor, 1'000'000);
assert(flux::read_at(seq, cursor) == 3); // still returning 3!
auto ctx = flux::iterate(rep);
assert(flux::next_element(ctx).value() == 3);
assert(flux::next_element(ctx).value() == 3);
assert(flux::next_element(ctx).value() == 3); // still returning 3!

// We could use the take adaptor to make a repeat sequence finite...
auto taken = flux::take(seq, 5);
auto taken = flux::take(rep, 5);
assert(flux::equal(taken, std::array{3, 3, 3, 3, 3}));

// ...but it's easier to use repeat(val, count) instead
// ...but it's better to use repeat(val, count) instead, as this is random-access
auto police = flux::repeat("hello"sv, 3);
assert(flux::equal(police, std::array{"hello", "hello", "hello"}));
static_assert(flux::random_access_sequence<decltype(police)>);
}
30 changes: 14 additions & 16 deletions example/shortest_path.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@

using namespace std::string_literals;

auto intersperse = [](flux::sequence auto seq, std::string sep) -> flux::generator<std::string>
{
auto intersperse
= [](flux::sequence auto seq, std::string sep) -> flux::generator<std::string const&> {
bool first = true;
for (auto c: seq) {
if (first) {
Expand All @@ -35,9 +35,7 @@ auto intersperse = [](flux::sequence auto seq, std::string sep) -> flux::generat
};

namespace color {
std::string yellow(const std::string& s) {
return "\u001b[33m"s + s + "\u001b[37m";
}
std::string yellow(const std::string& s) { return "\u001b[33m"s + s + "\u001b[37m"; }
}

class maze {
Expand Down Expand Up @@ -66,7 +64,7 @@ class maze {
width_(width),
height_(height),
fields_(width * height, 0)
{
{
assert(width > 1 && height > 1);
}

Expand All @@ -75,7 +73,7 @@ class maze {
std::mt19937 rng(seed);
std::uniform_int_distribution dist(1, 9);
maze m(width, height);

for (auto i: flux::ints(1, flux::size(m.fields_) - 1)) {
m.fields_[size_t(i)] = (rng() % 4) == 0 ? wall : dist(rng);
}
Expand All @@ -87,13 +85,13 @@ class maze {
auto to_char = [print_costs] (int num) {
if (num == wall) { return "#"s; }
if (num == path) { return color::yellow("*"); }
return print_costs ? std::to_string(num) : " "s;
return print_costs ? std::to_string(num) : " "s;
};
auto width = width_ * 2 + 3;
auto edge = flux::single("|"s);
auto h_edge = "+"s + std::string(width - 2, '-') + "+\n"s;
auto out = std::ostream_iterator<std::string>(s);

s << h_edge;
for (auto&& row: flux::ref(fields_).map(to_char).chunk(width_)) {
intersperse(flux::chain(flux::ref(edge), FLUX_FWD(row), flux::ref(edge)), " "s).output_to(out);
Expand All @@ -108,15 +106,13 @@ class maze {
std::vector<flux::optional<int>> costs(fields_.size());
std::vector<flux::optional<size_t>> prevs(fields_.size());

auto valid = [this](std::size_t u) {
return fields_[u] != wall;
};
auto valid = [this](std::size_t u) { return fields_[u] != wall; };

auto to_adjacent_edges = [this](std::size_t u) {
auto to_edge = [](auto e) { return edge_t{std::get<0>(e), std::get<1>(e)}; };
return flux::cartesian_product(flux::single(u), adjacent(u)).map(to_edge) ;
};

bool updated = false;
auto update_costs_and_prevs = [this, &costs, &prevs, &updated](edge_t e) {
constexpr auto max = std::numeric_limits<int>::max();
Expand All @@ -131,7 +127,7 @@ class maze {
do {
updated = false;
flux::iota(size_t{0}, fields_.size())
.filter(valid)
.filter(valid)
.map(to_adjacent_edges)
.flatten()
.for_each(update_costs_and_prevs);
Expand All @@ -143,8 +139,10 @@ class maze {
}
};

void print_side_by_side(std::istream& s1, std::istream& s2) {
for (auto [line1, line2]: flux::zip(flux::getlines(s1, '\n'), flux::getlines(s2, '\n'))) {
void print_side_by_side(std::istream& s1, std::istream& s2)
{
// FIXME: Remove as_range when we can
for (auto [line1, line2] : flux::zip(flux::getlines(s1, '\n'), flux::getlines(s2, '\n'))) {
std::cout << line1 << " " << line2 << '\n';
}
}
Expand Down
7 changes: 3 additions & 4 deletions example/top10/01_trapping_rain_water.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@

#include <flux.hpp>

auto const rain_water = [](std::initializer_list<int> heights)
{
auto const rain_water = []<std::size_t N>(std::array<int, N> heights) {
// Find the index of the maximum height
flux::cursor auto max_idx = flux::find_max(heights);

Expand All @@ -37,7 +36,7 @@ auto const rain_water = [](std::initializer_list<int> heights)
return trapped(left) + trapped(flux::reverse(right));
};

static_assert(rain_water({0,1,0,2,1,0,1,3,2,1,2,1}) == 6);
static_assert(rain_water({4,2,0,3,2,5}) == 9);
static_assert(rain_water(std::array{0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1}) == 6);
static_assert(rain_water(std::array{4, 2, 0, 3, 2, 5}) == 9);

int main() {}
2 changes: 1 addition & 1 deletion example/top10/08_three_consecutive_odds.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace version1 {
auto const tco = [](std::initializer_list<int> nums)
{
int odd_count = 0;
auto idx = flux::for_each_while(nums, [&](int i) {
auto idx = flux::seq_for_each_while(nums, [&](int i) {
if (i % 2 != 0) {
++odd_count;
} else {
Expand Down
5 changes: 2 additions & 3 deletions example/top10/09_skyline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,13 @@

#include <flux.hpp>

auto const skyline = [](std::initializer_list<int> heights)
{
auto const skyline = [](auto heights) {
auto h = flux::ref(heights);

return 1 + flux::zip(flux::drop(h, 1), flux::scan(h, flux::cmp::max))
.count_if([](auto p) { return p.first > p.second; });
};

static_assert(skyline({5, 5, 2, 10, 3, 15, 10}) == 3);
static_assert(skyline(std::array{5, 5, 2, 10, 3, 15, 10}) == 3);

int main() {}
6 changes: 2 additions & 4 deletions example/word_count.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,9 @@ struct stats_t
bool is_last_space = true;
};

auto collect_stats = [](flux::sequence auto&& seq)
{
auto collect_stats = [](flux::iterable auto&& seq) {
stats_t stats;
flux::for_each(FLUX_FWD(seq), [&stats](char val)
{
flux::for_each(FLUX_FWD(seq), [&stats](char val) {
stats.chars++;
if (not stats.is_last_space and std::isspace(val)) {
stats.words++;
Expand Down
2 changes: 1 addition & 1 deletion include/flux.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@
#include <flux/adaptor.hpp>
#include <flux/algorithm.hpp>
#include <flux/core.hpp>
#include <flux/sequence.hpp>
#include <flux/factory.hpp>

#endif
Loading
Loading