All checks were successful
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 9m28s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 8m25s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 9m4s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 10m27s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 9m36s
Build Packages / Generate python client (push) Successful in 32s
Build Packages / Build documentation (push) Successful in 45s
Build Packages / Create release (push) Has been skipped
Build Packages / build:rpm (rocky8) (push) Successful in 8m45s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 7m51s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 8m57s
Build Packages / build:rpm (rocky9) (push) Successful in 9m35s
Build Packages / Unit tests (push) Successful in 1h13m45s
This is an UNSTABLE release. * jfjoch_broker: Report changes in the image buffer, so viewer doesn't reload constantly * jfjoch_viewer: Improve performance of loading images * jfjoch_viewer: Auto-throttle image loading in HTTP-sync / movie modes * jfjoch_viewer: Auto-foreground calculated with histogram * jfjoch_viewer: Fix rare segmentation fault Reviewed-on: #28 Co-authored-by: Filip Leonarski <filip.leonarski@psi.ch> Co-committed-by: Filip Leonarski <filip.leonarski@psi.ch>
86 lines
2.5 KiB
C++
86 lines
2.5 KiB
C++
// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#ifndef JFJOCH_TOPPIXELS_H
|
|
#define JFJOCH_TOPPIXELS_H
|
|
|
|
#include <array>
|
|
#include <algorithm>
|
|
#include <cstdint>
|
|
#include <stdexcept>
|
|
#include <vector>
|
|
|
|
class TopPixels {
|
|
public:
|
|
struct Entry {
|
|
int32_t value = 0;
|
|
int32_t index = 0;
|
|
};
|
|
|
|
explicit TopPixels(int capacity = 20)
|
|
: capacity_(std::clamp(capacity, 1, kMaxCapacity)) {}
|
|
|
|
void Clear() noexcept { size_ = 0; }
|
|
|
|
void Add(int32_t value, int32_t index) noexcept {
|
|
const Entry e{value, index};
|
|
|
|
if (size_ < capacity_) {
|
|
InsertSorted_(e);
|
|
return;
|
|
}
|
|
|
|
// Quick reject: if not better than the current smallest in top-K
|
|
if (value <= top_[capacity_ - 1].value)
|
|
return;
|
|
|
|
ReplaceSmallestAndFixOrder_(e);
|
|
}
|
|
|
|
[[nodiscard]] int Capacity() const noexcept { return capacity_; }
|
|
[[nodiscard]] int Size() const noexcept { return size_; }
|
|
[[nodiscard]] bool Empty() const noexcept { return size_ == 0; }
|
|
|
|
// Sorted descending by value; valid for i in [0, Size()).
|
|
[[nodiscard]] const Entry& At(int i) const {
|
|
if (i < 0 || i >= size_)
|
|
throw std::out_of_range("TopPixels::At index out of range");
|
|
return top_[i];
|
|
}
|
|
|
|
[[nodiscard]] const Entry& operator[](int i) const { return At(i); }
|
|
|
|
// Convenience: copy results to a std::vector (still sorted descending).
|
|
[[nodiscard]] std::vector<Entry> ToVector() const {
|
|
return std::vector<Entry>(top_.begin(), top_.begin() + size_);
|
|
}
|
|
|
|
private:
|
|
static constexpr int kMaxCapacity = 64; // hard cap for stack-friendly storage
|
|
|
|
std::array<Entry, kMaxCapacity> top_{};
|
|
int size_ = 0;
|
|
int capacity_ = 20;
|
|
|
|
void InsertSorted_(Entry e) noexcept {
|
|
top_[size_] = e;
|
|
++size_;
|
|
|
|
// Bubble up to keep descending order by value
|
|
for (int i = size_ - 1; i > 0 && top_[i].value > top_[i - 1].value; --i)
|
|
std::swap(top_[i], top_[i - 1]);
|
|
}
|
|
|
|
void ReplaceSmallestAndFixOrder_(Entry e) noexcept {
|
|
// Replace the smallest (last, because sorted descending)
|
|
top_[capacity_ - 1] = e;
|
|
|
|
// Bubble up to restore descending order
|
|
for (int i = capacity_ - 1; i > 0 && top_[i].value > top_[i - 1].value; --i)
|
|
std::swap(top_[i], top_[i - 1]);
|
|
|
|
size_ = capacity_;
|
|
}
|
|
};
|
|
|
|
#endif //JFJOCH_TOPPIXELS_H
|