Commit 52bf9a6d authored by Baptiste Esteban's avatar Baptiste Esteban
Browse files

Apply MR suggested changes for directional hqueue

parent 8754f621
Pipeline #28152 failed with stage
in 27 minutes and 38 seconds
......@@ -46,7 +46,6 @@ namespace mln::morpho
requires(std::is_integral_v<W>&& std::is_unsigned_v<W> && sizeof(W) <= 2) class alphatree_edges<P, N, W>
{
public:
alphatree_edges(){};
void push(std::size_t dir, W w, P p) { m_cont.insert(dir, w, p); }
std::tuple<P, P, W> pop() { return m_cont.pop(); }
W top() const { return m_cont.current_level(); }
......@@ -69,10 +68,6 @@ namespace mln::morpho
class alphatree_edges
{
public:
alphatree_edges()
: m_current(0)
{
}
void push(std::size_t dir, W w, P p) { m_cont.push_back({p, p + cn.after_offsets()[dir], w}); }
std::tuple<P, P, W> pop()
{
......@@ -95,7 +90,7 @@ namespace mln::morpho
private:
static constexpr auto cn = N();
std::vector<edge_t<P, W>> m_cont;
std::size_t m_current;
std::size_t m_current = 0;
};
......@@ -153,16 +148,12 @@ namespace mln::morpho
}
template <class I, class N, class F>
auto alphatree_compute_edges(I input, N nbh, F distance)
template <class I, class N, class F, class C>
void alphatree_compute_edges(I input, N nbh, F distance, C& edges)
{
static_assert(is_a_v<I, mln::details::Image>);
using V = image_value_t<I>;
using P = image_point_t<I>;
using W = std::invoke_result_t<F, V, V>;
auto edges = alphatree_edges<P, N, W>();
auto dom = input.domain();
auto dom = input.domain();
mln_foreach (auto p, dom)
{
std::size_t i = 0;
......@@ -174,7 +165,6 @@ namespace mln::morpho
}
}
edges.on_finish_insert();
return edges;
}
//
......@@ -257,7 +247,7 @@ namespace mln::morpho
std::vector<int> translation_map(node_count);
translation_map[0] = 0;
int count = 1;
int count = 1;
// Build canonized component tree
for (std::size_t i = 1; i < node_count; ++i)
......@@ -292,7 +282,8 @@ namespace mln::morpho
static_assert(std::is_same<M, edge_t<P, W>>());
// 1. Get the list of edges
auto edges = internal::alphatree_compute_edges(std::move(input), std::move(nbh), std::move(distance));
auto edges = alphatree_edges<P, N, W>();
internal::alphatree_compute_edges(std::move(input), std::move(nbh), std::move(distance), edges);
std::size_t flatzones_count;
image_ch_value_t<I, int> node_map = imchvalue<int>(input).set_init_value(-1);
......
......@@ -4,15 +4,12 @@
#include <mln/core/concepts/neighborhood.hpp>
#include <mln/morpho/private/hvector_unbounded.hpp>
#include <array>
#include <memory>
namespace mln::morpho::details
{
/// \brief Directional hierarchical queue
/// \tparam I The image the edges are calculated from
/// \tparam P The point type stored in the queue
/// \tparam N The neighborhood used to compute the edges
/// \tparam K Value type of the level (Should be unsigned integer of at least a size of 2)
/// \tparam K Value type of the level (Should be unsigned and ``sizeof(K) <= 2 bytes``)
template <typename P, typename N, typename K>
class directional_hqueue
{
......@@ -20,14 +17,14 @@ namespace mln::morpho::details
using queue_type = hvectors_unbounded<P>;
public:
/// \brief Constructor
/// Constructor
directional_hqueue() noexcept;
/// \brief Insert an point in the directional hierarchical queue
/// \param dir The hierarchical queue index (from after_offset() in N)
/// \param w The weight of the edge
/// \param p The point the edge weight is calculated from
void insert(std::size_t dir, int w, P p) noexcept;
void insert(int dir, int w, P p) noexcept;
/// \brief Return the tuple (p, q, w) where p and q are the vertex of the edge and w its weight
std::tuple<P, P, int> pop() noexcept;
......@@ -43,12 +40,13 @@ namespace mln::morpho::details
static_assert(sizeof(K) <= 2, "Key should have a size of at least 2");
private:
static constexpr std::size_t m_ndir = decltype(N::after_offsets())::extent;
static constexpr int m_nlevels = 1 << std::numeric_limits<K>::digits;
std::array<std::shared_ptr<queue_type>, m_ndir> m_queues;
std::size_t m_current_dir;
int m_current_level;
std::size_t m_size;
static constexpr std::size_t m_ndir = decltype(N::after_offsets())::extent;
static constexpr int m_nlevels = 1 << std::numeric_limits<K>::digits;
queue_type m_queues[m_ndir];
int m_current_dir;
int m_current_level;
std::size_t m_size = 0;
};
/******************
......@@ -57,16 +55,15 @@ namespace mln::morpho::details
template <typename P, typename N, typename K>
directional_hqueue<P, N, K>::directional_hqueue() noexcept
: m_current_dir(0)
, m_current_level(0)
, m_size(0)
{
for (std::size_t i = 0; i < m_ndir; i++)
m_queues[i] = std::make_shared<queue_type>(m_nlevels);
{
m_queues[i].initialize(m_nlevels, sizeof(P));
}
}
template <typename P, typename N, typename K>
void directional_hqueue<P, N, K>::insert(std::size_t dir, int w, P p) noexcept
void directional_hqueue<P, N, K>::insert(int dir, int w, P p) noexcept
{
// Update the current level and the current dir to keep the queue sorted
if (m_size == 0 || w < m_current_level)
......@@ -74,7 +71,7 @@ namespace mln::morpho::details
m_current_dir = dir;
m_current_level = w;
}
m_queues[dir]->push_front(w, p);
m_queues[dir].push_front(w, p);
m_size++;
}
......@@ -82,19 +79,19 @@ namespace mln::morpho::details
std::tuple<P, P, int> directional_hqueue<P, N, K>::pop() noexcept
{
assert(m_size > 0);
const auto p = m_queues[m_current_dir]->pop_front(m_current_level);
const auto p = m_queues[m_current_dir].pop_front(m_current_level);
const auto q = p + N::after_offsets()[m_current_dir];
const int w = m_current_level;
m_size--;
// Update the current level and the current dir if needed
if (m_size > 0 && m_queues[m_current_dir]->empty(m_current_level))
if (m_size > 0 && m_queues[m_current_dir].empty(m_current_level))
{
int lvl = m_queues[0]->lower_bound(m_current_level);
int lvl = m_queues[0].lower_bound(m_current_level);
std::size_t dir = 0;
for (std::size_t i = 1; i < m_ndir; i++)
{
int tmp = m_queues[i]->lower_bound(m_current_level);
int tmp = m_queues[i].lower_bound(m_current_level);
if (tmp < lvl && tmp < m_nlevels)
{
lvl = tmp;
......
......@@ -8,7 +8,7 @@
#include <numeric>
namespace mln::morpho::details
namespace mln::morpho::details
{
......@@ -34,9 +34,11 @@ namespace mln::morpho::details
/// such that every queue at level x with 𝑙 < x ≤ level are empty.
int upper_bound(int level) const noexcept;
void initialize(int nlevel, std::size_t size);
protected:
hvectors_unbounded() = default;
/// \param nlevel Number of levels
/// \param size Size in bytes of an element
hvectors_unbounded(int nlevel, std::size_t size);
......@@ -49,9 +51,9 @@ namespace mln::morpho::details
/// Free the memory
void release();
virtual ~hvectors_unbounded() = default;
virtual ~hvectors_unbounded() = default;
virtual void uninitialized_copy_n(void* in, std::size_t count, void* out) = 0;
virtual void destroy_n(void* buffer, std::size_t count) = 0;
virtual void destroy_n(void* buffer, std::size_t count) = 0;
struct node_t
......@@ -61,8 +63,8 @@ namespace mln::morpho::details
int capacity;
};
node_t* m_lists; /* List of unitialized storage */
int m_nlevels;
node_t* m_lists = nullptr; /* List of unitialized storage */
int m_nlevels;
};
......@@ -70,39 +72,38 @@ namespace mln::morpho::details
class hvectors_unbounded final : public hvectors_unbounded<void>
{
public:
hvectors_unbounded() = default;
hvectors_unbounded(int nlevel);
~hvectors_unbounded() final;
hvectors_unbounded(const hvectors_unbounded&) = delete;
hvectors_unbounded(hvectors_unbounded&&) = delete;
hvectors_unbounded& operator= (const hvectors_unbounded&) = delete;
hvectors_unbounded& operator= (hvectors_unbounded&&) = delete;
hvectors_unbounded(hvectors_unbounded&&) = delete;
hvectors_unbounded& operator=(const hvectors_unbounded&) = delete;
hvectors_unbounded& operator=(hvectors_unbounded&&) = delete;
void push_front(int level, P p) noexcept;
P pop_front(int level) noexcept;
void push_front(int level, P p) noexcept;
P pop_front(int level) noexcept;
P back(int level) const noexcept;
P front(int level) const noexcept;
P back(int level) const noexcept;
P front(int level) const noexcept;
private:
void uninitialized_copy_n(void* in, std::size_t count, void* out) final;
void destroy_n(void* buffer, std::size_t count) final;
using base = hvectors_unbounded<void>;
};
/******************************************/
/**** Implementation ****/
/******************************************/
inline int hvectors_unbounded<void>::lower_bound(int level) const noexcept
{
assert(m_lists != nullptr);
mln_precondition(level < m_nlevels);
while (level < m_nlevels && m_lists[level].size == 0)
......@@ -112,6 +113,7 @@ namespace mln::morpho::details
inline int hvectors_unbounded<void>::upper_bound(int level) const noexcept
{
assert(m_lists != nullptr);
mln_precondition(level < m_nlevels);
while (level >= 0 && m_lists[level].size == 0)
......@@ -121,6 +123,7 @@ namespace mln::morpho::details
inline bool hvectors_unbounded<void>::empty(int level) const noexcept
{
assert(m_lists != nullptr);
return m_lists[level].size == 0;
}
......@@ -150,16 +153,15 @@ namespace mln::morpho::details
}
template <class P>
inline void hvectors_unbounded<P>::push_front(int level, P p) noexcept
{
assert(m_lists != nullptr);
if (m_lists[level].size == m_lists[level].capacity)
this->resize(level, sizeof(P));
P* buffer = reinterpret_cast<P*>(m_lists[level].begin);
P* e = buffer + m_lists[level].size++;
P* buffer = reinterpret_cast<P*>(m_lists[level].begin);
P* e = buffer + m_lists[level].size++;
new ((void*)e) P(p);
}
......@@ -178,7 +180,6 @@ namespace mln::morpho::details
}
template <class P>
inline P hvectors_unbounded<P>::front(int level) const noexcept
{
......@@ -189,4 +190,4 @@ namespace mln::morpho::details
}
} // namespace mln::morpho::detail
} // namespace mln::morpho::details
#include <mln/morpho/private/hvector_unbounded.hpp>
namespace mln::morpho::details
namespace mln::morpho::details
{
namespace
{
static constexpr int kInitReservationPerLevel = 256;
}
hvectors_unbounded<void>::hvectors_unbounded(int nlevel, std::size_t size)
hvectors_unbounded<void>::hvectors_unbounded(int nlevel, std::size_t size) { this->initialize(nlevel, size); }
void hvectors_unbounded<void>::initialize(int nlevel, std::size_t size)
{
constexpr std::size_t K = alignof(std::max_align_t);
std::size_t hdr_size = sizeof(node_t) * nlevel;
std::size_t data_size = size * nlevel * kInitReservationPerLevel;
std::size_t hdr_size = sizeof(node_t) * nlevel;
std::size_t data_size = size * nlevel * kInitReservationPerLevel;
std::size_t hdr_full_size = (hdr_size + (K - 1)) / K * K; // header with padding for alignment
std::size_t total_size = hdr_full_size + data_size;
std::size_t total_size = hdr_full_size + data_size;
assert(hdr_full_size % K == 0 && hdr_size <= hdr_full_size && hdr_full_size < hdr_size + K);
m_nlevels = nlevel;
m_nlevels = nlevel;
std::byte* buffer = (std::byte*)std::malloc(total_size);
m_lists = reinterpret_cast<node_t*>(buffer);
for (int i = 0; i < nlevel; ++i)
{
m_lists[i].size = 0;
m_lists[i].size = 0;
m_lists[i].capacity = kInitReservationPerLevel;
m_lists[i].begin = (void*) (buffer + hdr_full_size + size * kInitReservationPerLevel * i);
m_lists[i].begin = (void*)(buffer + hdr_full_size + size * kInitReservationPerLevel * i);
}
}
void hvectors_unbounded<void>::release()
{
assert(m_lists != nullptr);
for (int i = 0; i < m_nlevels; ++i)
{
this->destroy_n(m_lists[i].begin, m_lists[i].size);
......@@ -46,12 +48,13 @@ namespace mln::morpho::details
void hvectors_unbounded<void>::resize(int i, std::size_t size)
{
assert(m_lists != nullptr);
constexpr float kResizingFactor = 2;
int old_capacity = m_lists[i].capacity;
void* old_ptr = m_lists[i].begin;
int old_capacity = m_lists[i].capacity;
void* old_ptr = m_lists[i].begin;
m_lists[i].capacity = (int)(old_capacity * kResizingFactor);
m_lists[i].begin = std::malloc(size * m_lists[i].capacity);
m_lists[i].begin = std::malloc(size * m_lists[i].capacity);
this->uninitialized_copy_n(old_ptr, m_lists[i].size, m_lists[i].begin);
this->destroy_n(old_ptr, m_lists[i].size);
......@@ -60,4 +63,4 @@ namespace mln::morpho::details
std::free(old_ptr);
}
}
} // namespace mln::morpho::details
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment