OXYGENHUB
◆ main openmsx / src / utils / subrange_between.hh
1.4 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#ifndef SUBRANGE_BETWEEN_HH
2
#define SUBRANGE_BETWEEN_HH
3
4
#include <algorithm>
5
#include <functional>
6
#include <ranges>
7
8
// subrange_between
9
//
10
// Find the subrange of all elements whose projected value lies in [l, h).
11
//
12
// This is equivalent to:
13
//   first = lower_bound(r, l, comp, proj);
14
//   last  = lower_bound(r, h, comp, proj);
15
//
16
// We implement this using a single equal_range() by mapping the range
17
// into three monotonic regions (-1, 0, +1) via a projection, and then
18
// searching for the contiguous block equal to 0.
19
//
20
// Parameters:
21
//   r    - a sorted forward range
22
//   l, h - lower and upper bound (half-open interval [l, h))
23
//   comp - optional comparator (default: std::ranges::less)
24
//   proj - optional projection (default: std::identity)
25
template<std::ranges::forward_range R,
26
         typename T,
27
         typename Comp = std::ranges::less,
28
         typename Proj = std::identity>
29
auto subrange_between(R&& r, const T& l, const T& h, Comp comp = {}, Proj proj = {})
30
{
31
	// Projection mapping: -1 if x<l, 0 if l<=x<h, +1 if h<=x
32
	auto map_range = [l,h,&comp,&proj](const auto& x) -> int {
33
		auto val = std::invoke(proj, x);
34
		if (std::invoke(comp, val, l)) return -1;  // val < l
35
		if (!std::invoke(comp, val, h)) return 1;  // h <= val
36
		return 0;                                  // l <= val < h
37
	};
38
39
	auto [first, last] = std::ranges::equal_range(r, 0, std::ranges::less{}, map_range);
40
	return std::ranges::subrange(first, last);
41
}
42
43
#endif