CoolProp 8.0.0
An open-source fluid property and humid air property database
RegionAtlas.cpp
Go to the documentation of this file.
2
3namespace CoolProp {
4namespace region {
5
6std::size_t RegionAtlas::add(Region region) {
7 // Transactional insertion: every container must end up with the
8 // same size, or none of them grow. A throw mid-sequence would
9 // otherwise leave the SoA AABB cache and regions_ out of sync, so
10 // subsequent find_region calls would mis-dispatch.
11 //
12 // Snapshot the BBox before the std::move below — Region's custom
13 // move op invalidates the source's bbox_ (to defend against
14 // dangling-curve-pointer accesses on moved-from regions), so a
15 // reference taken pre-move would read sentinel values after.
16 const Region::BBox bbox = region.bbox();
17 const std::size_t old_size = regions_.size();
18 try {
19 regions_.push_back(std::move(region));
20 a_lo_.push_back(bbox.a_lo);
21 a_hi_.push_back(bbox.a_hi);
22 b_min_.push_back(bbox.b_min);
23 b_max_.push_back(bbox.b_max);
24 } catch (...) {
25 // Region has a deleted copy constructor (it owns std::unique_ptr
26 // members), so resize() can't be used here — it would require
27 // DefaultInsertable on the value type for the (potential) grow
28 // path. erase() is the right tool: shrink-only, no default
29 // construction needed.
30 if (regions_.size() > old_size) {
31 regions_.erase(regions_.begin() + static_cast<std::ptrdiff_t>(old_size), regions_.end());
32 }
33 if (a_lo_.size() > old_size) {
34 a_lo_.erase(a_lo_.begin() + static_cast<std::ptrdiff_t>(old_size), a_lo_.end());
35 }
36 if (a_hi_.size() > old_size) {
37 a_hi_.erase(a_hi_.begin() + static_cast<std::ptrdiff_t>(old_size), a_hi_.end());
38 }
39 if (b_min_.size() > old_size) {
40 b_min_.erase(b_min_.begin() + static_cast<std::ptrdiff_t>(old_size), b_min_.end());
41 }
42 if (b_max_.size() > old_size) {
43 b_max_.erase(b_max_.begin() + static_cast<std::ptrdiff_t>(old_size), b_max_.end());
44 }
45 throw;
46 }
47 return old_size;
48}
49
50int RegionAtlas::find_region(double a, double b) const noexcept {
51 const std::size_t n = regions_.size();
52 for (std::size_t i = 0; i < n; ++i) {
53 // AABB filter — cache-friendly first pass. Positive form so
54 // NaN inputs are correctly rejected (every comparison returns
55 // false; the previous negated form `a < a_lo_[i] || ...` was
56 // C++ UB on NaN — none of the `continue`s fired and locate_piece
57 // cast NaN to ptrdiff_t).
58 if (!(a >= a_lo_[i] && a <= a_hi_[i] && b >= b_min_[i] && b <= b_max_[i])) {
59 continue;
60 }
61 // AABB hit — confirm against the curved envelope.
62 if (regions_[i].curve_contains(a, b)) {
63 return static_cast<int>(i);
64 }
65 }
66 return -1;
67}
68
69std::vector<std::size_t> RegionAtlas::find_all_curve_hits(double a, double b) const {
70 std::vector<std::size_t> hits;
71 const std::size_t n = regions_.size();
72 for (std::size_t i = 0; i < n; ++i) {
73 if (!(a >= a_lo_[i] && a <= a_hi_[i] && b >= b_min_[i] && b <= b_max_[i])) {
74 continue;
75 }
76 if (regions_[i].curve_contains(a, b)) {
77 hits.push_back(i);
78 }
79 }
80 return hits;
81}
82
83} // namespace region
84} // namespace CoolProp