mirror of
https://github.com/boostorg/histogram.git
synced 2025-05-11 13:14:06 +00:00
Fixes possible pointer arithmetic past end position in indexed
This commit is contained in:
parent
3dff0438ea
commit
87e757f9e1
@ -132,8 +132,7 @@ public:
|
|||||||
/// Access indices as an iterable range.
|
/// Access indices as an iterable range.
|
||||||
index_view indices() const noexcept {
|
index_view indices() const noexcept {
|
||||||
BOOST_ASSERT(iter_.indices_.hist_);
|
BOOST_ASSERT(iter_.indices_.hist_);
|
||||||
return {iter_.indices_.data(),
|
return {iter_.indices_.begin(), iter_.indices_.end()};
|
||||||
iter_.indices_.data() + iter_.indices_.hist_->rank()};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access current bin.
|
/// Access current bin.
|
||||||
@ -239,18 +238,20 @@ public:
|
|||||||
pointer operator->() noexcept { return pointer_proxy{operator*()}; }
|
pointer operator->() noexcept { return pointer_proxy{operator*()}; }
|
||||||
|
|
||||||
iterator& operator++() {
|
iterator& operator++() {
|
||||||
BOOST_ASSERT(indices_.hist_);
|
BOOST_ASSERT(iter_ < indices_.hist_->end());
|
||||||
std::size_t stride = 1;
|
const auto cbeg = indices_.begin();
|
||||||
auto c = indices_.begin();
|
auto c = cbeg;
|
||||||
++c->idx;
|
|
||||||
++iter_;
|
++iter_;
|
||||||
while (c->idx == c->end && (c != (indices_.end() - 1))) {
|
++c->idx;
|
||||||
c->idx = c->begin;
|
if (c->idx < c->end) return *this;
|
||||||
iter_ -= (c->end - c->begin) * stride;
|
while (c->idx == c->end) {
|
||||||
stride *= c->extent;
|
iter_ += c->end_skip;
|
||||||
++c;
|
if (++c == indices_.end()) return *this;
|
||||||
++c->idx;
|
++c->idx;
|
||||||
iter_ += stride;
|
}
|
||||||
|
while (c-- != cbeg) {
|
||||||
|
c->idx = c->begin;
|
||||||
|
iter_ += c->begin_skip;
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -264,52 +265,70 @@ public:
|
|||||||
bool operator==(const iterator& x) const noexcept { return iter_ == x.iter_; }
|
bool operator==(const iterator& x) const noexcept { return iter_ == x.iter_; }
|
||||||
bool operator!=(const iterator& x) const noexcept { return !operator==(x); }
|
bool operator!=(const iterator& x) const noexcept { return !operator==(x); }
|
||||||
|
|
||||||
|
// make iterator ready for C++17 sentinels
|
||||||
|
bool operator==(const value_iterator& x) const noexcept { return iter_ == x; }
|
||||||
|
bool operator!=(const value_iterator& x) const noexcept { return !operator==(x); }
|
||||||
|
|
||||||
|
// useful for iterator debugging
|
||||||
|
std::size_t offset() const noexcept { return iter_ - indices_.hist_->begin(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
iterator(histogram_type* h) : iter_(h->begin()), indices_(h) {}
|
iterator(value_iterator i, histogram_type& h) : iter_(i), indices_(&h) {}
|
||||||
|
|
||||||
value_iterator iter_;
|
value_iterator iter_;
|
||||||
|
|
||||||
struct index_data {
|
struct index_data {
|
||||||
axis::index_type idx, begin, end, extent;
|
axis::index_type idx, begin, end;
|
||||||
|
std::size_t begin_skip, end_skip;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct indices_t : std::array<index_data, buffer_size> {
|
struct indices_t : private std::array<index_data, buffer_size> {
|
||||||
using base_type = std::array<index_data, buffer_size>;
|
using base_type = std::array<index_data, buffer_size>;
|
||||||
|
using pointer = index_data*;
|
||||||
|
using const_pointer = const index_data*;
|
||||||
|
|
||||||
indices_t(histogram_type* h) noexcept : hist_{h} {}
|
indices_t(histogram_type* h) noexcept : hist_{h} {}
|
||||||
|
|
||||||
constexpr auto end() noexcept { return base_type::begin() + hist_->rank(); }
|
using base_type::operator[];
|
||||||
constexpr auto end() const noexcept { return base_type::begin() + hist_->rank(); }
|
unsigned size() const noexcept { return hist_->rank(); }
|
||||||
|
pointer begin() noexcept { return base_type::data(); }
|
||||||
|
const_pointer begin() const noexcept { return base_type::data(); }
|
||||||
|
pointer end() noexcept { return begin() + size(); }
|
||||||
|
const_pointer end() const noexcept { return begin() + size(); }
|
||||||
|
|
||||||
histogram_type* hist_;
|
histogram_type* hist_;
|
||||||
} indices_;
|
} indices_;
|
||||||
|
|
||||||
friend class indexed_range;
|
friend class indexed_range;
|
||||||
};
|
};
|
||||||
|
|
||||||
indexed_range(histogram_type& hist, coverage cov) : begin_(&hist), end_(&hist) {
|
indexed_range(histogram_type& hist, coverage cov)
|
||||||
std::size_t stride = 1;
|
: begin_(hist.begin(), hist), end_(hist.end(), hist) {
|
||||||
auto ca = begin_.indices_.begin();
|
begin_.indices_.hist_->for_each_axis([ca = begin_.indices_.begin(), cov,
|
||||||
const auto clast = ca + begin_.indices_.hist_->rank() - 1;
|
stride = std::size_t{1},
|
||||||
begin_.indices_.hist_->for_each_axis(
|
this](const auto& a) mutable {
|
||||||
[ca, clast, cov, &stride, this](const auto& a) mutable {
|
using opt = axis::traits::static_options<std::decay_t<decltype(a)>>;
|
||||||
using opt = axis::traits::static_options<std::decay_t<decltype(a)>>;
|
constexpr axis::index_type under = opt::test(axis::option::underflow);
|
||||||
constexpr int under = opt::test(axis::option::underflow);
|
constexpr axis::index_type over = opt::test(axis::option::overflow);
|
||||||
constexpr int over = opt::test(axis::option::overflow);
|
const auto size = a.size();
|
||||||
const auto size = a.size();
|
|
||||||
|
|
||||||
ca->extent = size + under + over;
|
// -1 if underflow and cover all, else 0
|
||||||
// -1 if underflow and cover all, else 0
|
ca->begin = cov == coverage::all ? -under : 0;
|
||||||
ca->begin = cov == coverage::all ? -under : 0;
|
// size + 1 if overflow and cover all, else size
|
||||||
// size + 1 if overflow and cover all, else size
|
ca->end = cov == coverage::all ? size + over : size;
|
||||||
ca->end = cov == coverage::all ? size + over : size;
|
ca->idx = ca->begin;
|
||||||
ca->idx = ca->begin;
|
|
||||||
|
|
||||||
begin_.iter_ += (ca->begin + under) * stride;
|
// if axis has *flow and coverage::all OR axis has no *flow:
|
||||||
end_.iter_ += ((ca < clast ? ca->begin : ca->end) + under) * stride;
|
// begin + under == 0, size + over - end == 0
|
||||||
|
// if axis has *flow and coverage::inner:
|
||||||
|
// begin + under == 1, size + over - end == 1
|
||||||
|
ca->begin_skip = static_cast<std::size_t>(ca->begin + under) * stride;
|
||||||
|
ca->end_skip = static_cast<std::size_t>(size + over - ca->end) * stride;
|
||||||
|
begin_.iter_ += ca->begin_skip;
|
||||||
|
|
||||||
stride *= ca->extent;
|
stride *= size + under + over;
|
||||||
++ca;
|
++ca;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator begin() noexcept { return begin_; }
|
iterator begin() noexcept { return begin_; }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user