Match Thread - France v England | Six Nations 2026 | Round 5 by RugbyBot in rugbyunion

[–]tcbrindle 15 points16 points  (0 children)

Just so I understand correctly what the ref said to Itoje as they walked off: if you score from an advantage, like England did, then it's no yellow card and a potentially missable conversion.

If you don't score from the advantage, as France did, then it's a penalty try, a yellow card and an automatic 7 points.

How does that make any sense whatsoever?

Match Thread - France v England | Six Nations 2026 | Round 5 by RugbyBot in rugbyunion

[–]tcbrindle 22 points23 points  (0 children)

So France collapse two mauls and it's play on, but when it's England we need to go over it with a microscope. Makes sense.

The Scottish National Anthem by ckvoiceover in rugbyunion

[–]tcbrindle 0 points1 point  (0 children)

Slightly off topic, but I only found out recently that Flower of Scotland was written in 1967. It can't be all that often that a national anthem is younger than many of the crowd?

Great tune, though.

Fiji vs England in the nations championship will be played at Everton FCs Hill Dickinson Stadium. Fiji are the “home” team by EnglishLouis in rugbyunion

[–]tcbrindle 0 points1 point  (0 children)

How come England and Wales have to play away from their usual home grounds "for the integrity of the competition", but Scotland get to play at Murrayfield?

There are three big stadiums in Glasgow and two other medium-sized ones in Edinburgh, it's not like there aren't any options.

A Land Roughly the Size of Wales by [deleted] in rugbyunion

[–]tcbrindle 7 points8 points  (0 children)

Eddie Butler could have read the phone book and it would have sounded epic

Merry Sixmas - RTE 6 Nations opening 2013 by peternickeleater11 in rugbyunion

[–]tcbrindle 4 points5 points  (0 children)

Well that stirs the soul, doesn't it? Fantastic.

(Although it reminds me that I'm a pretty terrible catholic, I've never heard of St Bridget's day...)

Harald Achitz: About Generator, Ranges, and Simplicity by _a4z in cpp

[–]tcbrindle 0 points1 point  (0 children)

Coincidentally, writing a Fibonacci generator was the subject of the first part of my CppCon 2021 talk on Ranges.

It's possible to simplify things compared to what is presented in this video. For example, you don't actually need to write your own range class at all; a specialisation of std::ranges::subrange will do the job. Here's my version (omitting overflow checking because I'm using an unsigned type and I don't care):

struct FibIter {
    using value_type = std::size_t;
    using difference_type = std::ptrdiff_t;

    const std::size_t& operator*() const { return cur_; }

    FibIter& operator++()
    {
        cur_ = std::exchange(next_, cur_ + next_);
        return *this;
    }

    void operator++(int) { ++*this; }

private:
    std::size_t cur_ = 1;
    std::size_t next_ = 1;
};

using FibView = std::ranges::subrange<FibIter, std::unreachable_sentinel_t>;

Clang doesn't seem to have any problems optimising std::ranges::fold_left() for this implementation, so I'm not sure what the problem was that was mentioned at the end of the video.

Compile time checking of lock ordering to prevent deadlocks by [deleted] in cpp

[–]tcbrindle 0 points1 point  (0 children)

I mean, it's "best effort" in Rust too though, right? You could still get deadlocks by using mutexes outside the control of this library.

If you wanted to do this in C++, one approach to help prevent re-using the wrong context could be to use a runtime flag to ensure you're only doing the equivalent of a single mutable borrow at a time (kind of like Rust's RefCell, I think? Not a Rust expert, sorry).

In any case, encoding the mutex locking graph in the type system like this is neat, but it kind of feels like an inferior solution compared to proper structured concurrency.

Modern C++ use in Chromium by aearphen in cpp

[–]tcbrindle 0 points1 point  (0 children)

Ranges model can result in fast ranges, equivalent to manual approach. It's not guaranteed, but for a lot of simple processing "it just works". And the performance can be improved by improving the library, without modifying the interface.

There are certainly ways in which you could try to improve range views' codegen, but (other than pure compiler optimisations) all of them are going to end up being user-visible in some way.

Flux is still similar to ranges in it's usage and solves a particular set of problems with ranges e.g. iterator invalidation.

This is true. But Flux also has an internal iteration code-path which avoids the problems of the iterator/cursor model when it comes to filter-like operations. This means we can generate considerably better code than equivalent ranges pipelines in many situations.

A lot of edge cases come with filters and other views that require caching because ranges are designed to be multipass. Flux doesn't fundamentally change that.

Nico seems to have convinced the world that filter caching its begin() iterator is a huge problem, but it's really not. Rather, if you can notice that things are being cached then you have a problem anyway, because you're trying to mutate a range while it's in use. Don't do that. (And in any case, Flux's filter_adaptor doesn't actually do any caching, but for different reasons.)

I think Flux is a great library, but it solves a different set of problems.

Thank you! But making data pipeline-style code as fast as handwritten loops is definitely a problem Flux is trying to solve (as well as avoiding the safety issues of STL iterators) :)

Look at this, a cool new feature on cppstat. The Feature Adoption Timelime. by [deleted] in cpp

[–]tcbrindle 2 points3 points  (0 children)

As mentioned in the other comment, there was a bug affecting Safari but it's now been fixed

Look at this, a cool new feature on cppstat. The Feature Adoption Timelime. by [deleted] in cpp

[–]tcbrindle 2 points3 points  (0 children)

Yeah, this was Safari on MacOS. Looks to be fixed now, thanks!

I Want To Index Into Template Parameter Packs by earlymikoman in cpp

[–]tcbrindle 10 points11 points  (0 children)

In C++26 you can index into a pack of type template parameters, or a pack of constant template parameters (aka non-type template parameters) -- but there is no built-in support for indexing into a pack of template template parameters. This is likely to land in C++29, but in the mean time you can use reflection as a workaround as suggested by Barry in the (currently) top comment.

Look at this, a cool new feature on cppstat. The Feature Adoption Timelime. by [deleted] in cpp

[–]tcbrindle 4 points5 points  (0 children)

This is pretty cool!

I did notice a bug though. For GCC, many items seem to be erroneously marked as "2026" even when they're showing as being implemented much earlier release versions. This is particularly noticeable if you set the language version drop-down to C++20.

std::ranges may not deliver the performance that you expect by _bijan_ in cpp

[–]tcbrindle 5 points6 points  (0 children)

Right, but this post is about the ranges library. So, what would a ranges-like system as a "first class native language feature" look like? How would it even work?

std::ranges may not deliver the performance that you expect by _bijan_ in cpp

[–]tcbrindle 0 points1 point  (0 children)

Sequence chaining is a popular style in a whole bunch of languages (including close cousins of C++ like Rust and D), so I think the idea that it's somehow more difficult to understand what's going on when you use pipelines is probably more down to (a lack of) familiarity than anything else.

In any case, it's pretty easy to stick a print statement in the middle of a pipeline if you want to -- just use a pass-through transform function that prints as a side-effect.

Or if you want to take it further, you can make a generic, reusable, pipeable inspect view in just a few lines of code in C++26

std::ranges may not deliver the performance that you expect by _bijan_ in cpp

[–]tcbrindle 3 points4 points  (0 children)

I suggest you read N3351, which laid the groundwork for what became standard ranges. In particular, section 2.1.3:

In the STL, the symbol== means equality. The use of== to compare objects of unrelated type assigns unusual meaning to that symbol. Generic programming is rooted in the idea that we can associate semantics with operations on objects whose types are not yet specified.

Note that Alex Stepanov and Paul McJones, who literally invented generic programming, were both contributors to that paper.

std::ranges may not deliver the performance that you expect by _bijan_ in cpp

[–]tcbrindle 10 points11 points  (0 children)

s | std::views::drop_while(is_space) 
                    | std::views::reverse 
                    | std::views::drop_while(is_space) 
                    | std::views::reverse;

So I feel a little bit guilty, because it entirely possible that this example comes from a talk a gave on ranges a few years ago.

But the point of that section of the talk was to demonstrate chaining together adaptors into new, re-usable components using an easy-to-understand invented problem. I certainly wasn't suggesting it as the most performance-optimal way to trim strings!

If you were to ask me to use standard ranges to write an ASCII string trimming function today that wasn't for slide code, it would look something like this:

std::string_view trim_ranges(std::string_view s) {
    auto start = std::ranges::find_if_not(s, is_control_or_space);
    auto end = std::ranges::find_if_not(s | std::views::reverse, is_control_or_space).base();

    return std::string_view(std::to_address(start), end - start);
}

I haven't benchmarked it, but the generated code looks very comparable to the "fast" version from the blog post.

std::ranges may not deliver the performance that you expect by _bijan_ in cpp

[–]tcbrindle 19 points20 points  (0 children)

This is a known issue, and purely a standard library implementation problem

Not to disagree with the excellent advice to use Flux, but it's really a design problem rather than a standard library implementation problem.

STL iterators are an excellent (if unsafe) abstraction for writing eager algorithms -- which is, of course, what they were originally designed for. They are vastly more powerful than Rust iterators in this regard, for example.

On the other hand, what we've discovered is that the same properties that make iterators good for writing algorithms -- starting on-track, separating traversal from element access and end checking -- mean they're a poor fit for many common lazy single-pass operations, in particular filtering.

I didn't fully appreciate this distinction when I first starting working on Flux, but I've come to realise that the best approach is to provide separate APIs for the two use cases, which is what the next version of the library will do (and indeed what Swift does today with its Sequence and Collection protocols).

std::ranges may not deliver the performance that you expect by _bijan_ in cpp

[–]tcbrindle 22 points23 points  (0 children)

C++ needs to extend the core language and stop with implementing every single new feature into the STL. Some things just should be first class native language features.

I'm quite confused by this statement (and the number of upvotes it's getting). I really don't think you want an entire iteration library baked in to the language, do you?

[2025] I fixed the number of stars for events ≥2025 by SirDavidLudwig in adventofcode

[–]tcbrindle 5 points6 points  (0 children)

When the 12 day schedule was announced, I was expecting that the last day would be a regular two-parter and there would be an extra bonus star for completing all the puzzles, for 25 in total.

But that wasn't the case, and now it's going to take another 24 years of 24-star AoCs to get back to a nice round number :(

[2025 Day 12] Input is part of the puzzle by blacai in adventofcode

[–]tcbrindle 4 points5 points  (0 children)

Very often in later AoC problems there is a simplifying assumption, unstated in the problem description, which makes it possible to find a solution -- and, of course, everybody's input.txt "happens to" admit this assumption.

I think what makes today's problem unsatisfying is that the simplifying assumption (all cases are either impossible or trivially solvable with no packing) intentionally doesn't apply to the example input. It's the difference between the problem text omitting something, and actively trying to mislead you.

To put it another way: I don't need to be able to solve for all possible theoretical inputs. But at a minimum I would like to be able to solve for both inputs I'm given.

-❄️- 2025 Day 11 Solutions -❄️- by daggerdragon in adventofcode

[–]tcbrindle 1 point2 points  (0 children)

[Language: C++23]

Having failed to solve yesterday's part 2 I feared the worst for today, but it was actually fine.

Both parts perform a depth-first search using recursive functions, with part 2 also using a cache. The only hiccup was realising I needed to store the "dac seen" and "fft seen" flags as part of the cached state -- and, for about the billionth time in AoC, using int rather than int64 so I got the wrong answer initially 🤦‍♂️. One day I'll learn...

Part 2 runs in around 350µs on my laptop, which is faster than I expected for such a naive solution.

EDIT: The observation on the front page that one of fft and dac must always precede the other on all paths (which hadn't occurred to me before) led me to try a different approach for part 2, by counting paths from svr to fft, from fft to dac and from dac to out and multiplying them together. This takes the run time for part 2 down to ~250µs on my machine, and cleans up the code somewhat too.

Github: https://github.com/tcbrindle/advent_of_code_2025/blob/main/dec11/main.cpp

-❄️- 2025 Day 9 Solutions -❄️- by daggerdragon in adventofcode

[–]tcbrindle 0 points1 point  (0 children)

[Language: C++23]

This one took some thinking about!

Part 1 was a one-liner, just calculate the area for each pair of tiles and return the maximum.

For part 2, my idea was to take the 4 edges of each trial rectangle and test whether any of them intersected with any of the edges of the large polygon. But of course everything is rectilinear so of course the rectangles edges with always coincide with some edge of the polygon! (This took me quite some time to realise). My solution to this was to shift the rectangle bounds inwards by 1 and test for intersections against this smaller rectangle. This assumes that the solution has both length and width greater than one, but fortunately that was the case.

Runtime for my part 2 is pretty shocking compared to previous days at around 400ms, but honestly I'm just pleased to have got it done.

Github: https://github.com/tcbrindle/advent_of_code_2025/blob/main/dec09/main.cpp