Program Listing for File Ordered.hpp
↰ Return to documentation for file (src/navtk/utils/Ordered.hpp)
#pragma once
#include <deque>
#include <navtk/utils/RingBuffer.hpp>
#include <navtk/utils/algorithm.hpp>
namespace navtk {
namespace utils {
template <typename Data,
typename Container,
typename Compare,
typename SortIterator,
typename SortCompare>
class Ordered {
public:
using value_type = Data;
using iterator = typename Container::iterator;
using const_iterator = typename Container::const_iterator;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using const_iterator_pair = std::pair<const_iterator, const_iterator>;
using const_reverse_iterator_pair = std::pair<const_reverse_iterator, const_reverse_iterator>;
std::size_t size() const { return buffer.size(); }
bool empty() const { return buffer.empty(); }
bool full() const { return buffer.full(); }
void pop_front() { buffer.pop_front(); }
void pop_back() { buffer.pop_back(); }
const Data& front() const { return buffer.front(); }
const Data& back() const { return buffer.back(); }
iterator erase(const_iterator first, const_iterator last) { return buffer.erase(first, last); }
iterator begin() { return buffer.begin(); }
iterator end() { return buffer.end(); }
reverse_iterator rbegin() { return buffer.rbegin(); }
reverse_iterator rend() { return buffer.rend(); }
const_iterator begin() const { return buffer.begin(); }
const_iterator end() const { return buffer.end(); }
const_reverse_iterator rbegin() const { return buffer.rbegin(); }
const_reverse_iterator rend() const { return buffer.rend(); }
const_iterator cbegin() const { return buffer.cbegin(); }
const_iterator cend() const { return buffer.cend(); }
const_reverse_iterator crbegin() const { return buffer.crbegin(); }
const_reverse_iterator crend() const { return buffer.crend(); }
void insert(const Data& data) {
Compare compare;
if (is_insert_ok(data, buffer, capacity)) {
pre_insert(data, buffer, capacity);
bool sort_it = (!buffer.empty()) && (compare(data, buffer.back()));
// push data on the back of the buffer
buffer.push_back(data);
if (sort_it) {
// minor efficiency if inserted data is very near the end
auto begin_sort = std::upper_bound(buffer.begin(), buffer.end() - 1, data, compare);
std::stable_sort(begin_sort, buffer.end(), compare);
}
post_insert(data, buffer, capacity);
}
}
const_iterator_pair get_in_range(typename SortIterator::value_type t0,
typename SortIterator::value_type t1) const {
auto range =
in_range.get(SortIterator{buffer.cbegin()}, SortIterator{buffer.cend()}, t0, t1);
return std::make_pair(const_iterator{range.first}, const_iterator{range.second});
}
const_iterator_pair get_nearest_neighbors(const typename SortIterator::value_type& t) const {
auto neighbors =
nearest_neighbors.get(SortIterator{buffer.cbegin()}, SortIterator{buffer.cend()}, t);
return std::make_pair(const_iterator{neighbors.first}, const_iterator{neighbors.second});
}
protected:
Ordered(std::size_t capacity, std::size_t initial_capacity)
: capacity(capacity), buffer(Container(initial_capacity)) {}
virtual ~Ordered() = default;
Ordered(const Ordered&) = default;
Ordered& operator=(const Ordered&) = default;
Ordered(Ordered&&) = default;
Ordered& operator=(Ordered&&) = default;
private:
std::size_t capacity;
Container buffer;
virtual bool is_insert_ok(const Data&, const Container&, std::size_t) const { return true; }
virtual void pre_insert(const Data&, Container&, std::size_t) {}
virtual void post_insert(const Data&, Container&, std::size_t) {}
InRange<SortIterator, SortCompare> in_range;
NearestNeighbors<SortIterator, SortCompare> nearest_neighbors;
};
template <typename Data,
typename Compare = std::less<Data>,
typename SortIterator = typename RingBuffer<Data>::const_iterator,
typename SortCompare = std::less<Data>>
class OrderedRing final : public Ordered<Data,
typename navtk::utils::RingBuffer<Data>,
Compare,
SortIterator,
SortCompare> {
public:
explicit OrderedRing(std::size_t capacity)
: Ordered<Data, RingBuffer<Data>, Compare, SortIterator, SortCompare>(capacity, capacity) {}
private:
bool is_insert_ok(const Data& data,
const RingBuffer<Data>& buffer,
std::size_t capacity) const override {
// if the buffer is full and this element won't fit in order, return false
return !(buffer.size() == capacity && Compare()(data, buffer.front()));
}
};
template <typename Data,
typename Compare = std::less<Data>,
typename SortIterator = typename std::deque<Data>::const_iterator,
typename SortCompare = std::less<Data>>
class OrderedDeque final
: public Ordered<Data, typename std::deque<Data>, Compare, SortIterator, SortCompare> {
public:
explicit OrderedDeque(std::size_t capacity)
: Ordered<Data, std::deque<Data>, Compare, SortIterator, SortCompare>(capacity, 0) {}
private:
void post_insert(const Data&, std::deque<Data>& buffer, std::size_t capacity) override {
// if the buffer is over capacity remove an element from the front
if (buffer.size() > capacity) {
buffer.pop_front();
}
}
};
} // namespace utils
} // namespace navtk