Skip to content

Commit

Permalink
Merge pull request #19 from i80287/minor-update
Browse files Browse the repository at this point in the history
Minor update
  • Loading branch information
i80287 authored Dec 22, 2024
2 parents 8a94924 + 55627bf commit 80f05a4
Show file tree
Hide file tree
Showing 53 changed files with 1,463 additions and 848 deletions.
24 changes: 24 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,27 @@ BraceWrapping:
AlignConsecutiveAssignments: true
InsertNewlineAtEOF: true
AllowShortFunctionsOnASingleLine: Empty
StatementAttributeLikeMacros: [
ATTRIBUTE_CONST,
ATTRIBUTE_MAYBE_UNUSED,
ATTRIBUTE_PURE,
ATTRIBUTE_NOINLINE,
ATTRIBUTE_ALWAYS_INLINE,
ATTRIBUTE_COLD,
ATTRIBUTE_HOT,
ATTRIBUTE_ALLOC_SIZE,
ATTRIBUTE_ACCESS,
ATTRIBUTE_SIZED_ACCESS,
ATTRIBUTE_ACCESS_NONE,
ATTRIBUTE_NONNULL,
ATTRIBUTE_NONNULL_ALL_ARGS,
ATTRIBUTE_TARGET,
ATTRIBUTE_LIFETIME_BOUND,
ATTRIBUTE_REINITIALIZES,
ATTRIBUTE_NODISCARD,
ATTRIBUTE_NODISCARD_WITH_MESSAGE,
ATTRIBUTE_NORETURN,
ATTRIBUTE_NOTHROW,
ATTRIBUTE_FALLTHROUGH,
]
BinPackParameters: false
163 changes: 101 additions & 62 deletions DisjointSetUnion/dsu.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,27 @@
#include <cassert>
#include <cstddef>
#include <cstdint>
#if __cplusplus >= 202002L
#include <concepts>
#endif
#include <type_traits>
#include <utility>
#include <vector>

#include "../misc/config_macros.hpp"

#if CONFIG_HAS_CONCEPTS
#include <concepts>
#endif

#if (CONFIG_HAS_AT_LEAST_CXX_20 && !defined(_GLIBCXX_DEBUG) && !defined(_GLIBCXX_ASSERTIONS)) || \
CONFIG_HAS_AT_LEAST_CXX_23
#define CONSTEXPR_VECTOR constexpr
#else
#define CONSTEXPR_VECTOR inline
#endif

namespace dsu_impl {

using Weight = std::int64_t;

// Node with rank heuristic
struct dsu_node_t {
dsu_node_t* parent_{};
Expand All @@ -24,11 +36,11 @@ struct wdsu_node_t {
wdsu_node_t* parent_{};
std::size_t rank_{};
std::size_t set_size_ = 1; // node itself
std::int64_t weight_{};
Weight weight_{};
};

template <class node_type>
#if __cplusplus >= 202002L
#if CONFIG_HAS_CONCEPTS
requires requires(node_type node) {
{ node.parent_ } -> std::convertible_to<node_type*>;
{ node.set_size_ } -> std::convertible_to<std::size_t>;
Expand All @@ -48,63 +60,65 @@ class dsu_base {
using difference_type = typename container::difference_type;
using allocator_type = typename container::allocator_type;

constexpr size_type size() const noexcept {
[[nodiscard]] constexpr size_type size() const noexcept {
return nodes_.size();
}
constexpr size_type sets_size() const noexcept {
[[nodiscard]] constexpr size_type sets_size() const noexcept {
return sets_size_;
}
// O(1)
constexpr size_type set_size_of(size_type node_index) const noexcept {
[[nodiscard]] CONSTEXPR_VECTOR size_type set_size_of(size_type node_index) const noexcept {
assert(node_index < size());
const node_t& node = nodes_[node_index];
const_pointer parent_ptr = node.parent_;
return parent_ptr != nullptr ? parent_ptr->set_size_ : node.set_size_;
}
// O(log*(n)) = O(a(n))
constexpr size_type set_size_of(size_type node_index) noexcept {
[[nodiscard]] CONSTEXPR_VECTOR size_type set_size_of(size_type node_index) noexcept {
assert(node_index < size());
return findRoot(node_index)->set_size_;
return find_root(node_index)->set_size_;
}

protected:
constexpr dsu_base(size_type nodes_count) : nodes_(nodes_count), sets_size_(nodes_count) {}
constexpr dsu_base(const dsu_base& other) = default;
constexpr dsu_base& operator=(const dsu_base& other) = default;
constexpr dsu_base(dsu_base&& other) noexcept
CONSTEXPR_VECTOR dsu_base(size_type nodes_count)
: nodes_(nodes_count), sets_size_(nodes_count) {}
CONSTEXPR_VECTOR dsu_base(const dsu_base& other) = default;
CONSTEXPR_VECTOR dsu_base& operator=(const dsu_base& other) = default;
CONSTEXPR_VECTOR dsu_base(dsu_base&& other) noexcept
: nodes_(std::move(other.nodes_)), sets_size_(std::exchange(other.sets_size_, 0)) {}
constexpr dsu_base& operator=(dsu_base&& other) noexcept {
CONSTEXPR_VECTOR dsu_base& operator=(dsu_base&& other) noexcept {
swap(other);
return *this;
}
constexpr ~dsu_base() = default;
constexpr void swap(dsu_base& other) noexcept {
CONSTEXPR_VECTOR ~dsu_base() = default;
CONSTEXPR_VECTOR void swap(dsu_base& other) noexcept ATTRIBUTE_LIFETIME_BOUND {
nodes_.swap(other.nodes_);
std::swap(sets_size_, other.sets_size_);
}
constexpr const_pointer data() const noexcept {
[[nodiscard]] CONSTEXPR_VECTOR const_pointer data() const noexcept ATTRIBUTE_LIFETIME_BOUND {
return nodes_.data();
}
constexpr pointer data() noexcept {
[[nodiscard]] CONSTEXPR_VECTOR pointer data() noexcept ATTRIBUTE_LIFETIME_BOUND {
return nodes_.data();
}
constexpr void reset() noexcept(std::is_nothrow_default_constructible_v<value_type> &&
std::is_nothrow_copy_assignable_v<value_type> &&
std::is_nothrow_destructible_v<value_type>) {
CONSTEXPR_VECTOR void reset() noexcept(std::is_nothrow_default_constructible_v<value_type> &&
std::is_nothrow_copy_assignable_v<value_type> &&
std::is_nothrow_destructible_v<value_type>) {
std::fill_n(data(), size(), value_type{});
sets_size_ = size();
}
constexpr void clear() noexcept {
CONSTEXPR_VECTOR void clear() noexcept {
nodes_.clear();
}

constexpr bool equal(size_type lhs_node_index, size_type rhs_node_index) noexcept {
return findRoot(lhs_node_index) == findRoot(rhs_node_index);
[[nodiscard]] CONSTEXPR_VECTOR bool equal(size_type lhs_node_index,
size_type rhs_node_index) noexcept {
return find_root(lhs_node_index) == find_root(rhs_node_index);
}
constexpr pointer findRoot(size_type node_index) noexcept {
return findRoot(std::addressof(nodes_[node_index]));
[[nodiscard]] CONSTEXPR_VECTOR pointer find_root(size_type node_index) noexcept {
return find_root(std::addressof(nodes_[node_index]));
}
static constexpr pointer findRoot(pointer node) noexcept {
[[nodiscard]] static constexpr pointer find_root(pointer node) noexcept {
pointer current_node = node;
assert(current_node != nullptr);
while (current_node->parent_ != nullptr) {
Expand Down Expand Up @@ -136,9 +150,11 @@ class dsu_t final : public dsu_impl::dsu_base<dsu_impl::dsu_node_t> {
public:
dsu_t() = delete;

constexpr explicit dsu_t(size_type nodes_count) : base(nodes_count) {}

dsu_t(const dsu_t& other) : base(other) {
[[nodiscard]]
static CONSTEXPR_VECTOR dsu_t with_nodes_count(size_type nodes_count) {
return dsu_t{nodes_count};
}
CONSTEXPR_VECTOR dsu_t(const dsu_t& other) : base(other) {
node_t* const this_first_node = data();
const node_t* const other_first_node = other.data();

Expand All @@ -151,31 +167,33 @@ class dsu_t final : public dsu_impl::dsu_base<dsu_impl::dsu_node_t> {
: nullptr;
}
}
dsu_t& operator=(const dsu_t& other) {
CONSTEXPR_VECTOR dsu_t& operator=(const dsu_t& other) ATTRIBUTE_LIFETIME_BOUND {
return *this = dsu_t(other);
}
constexpr dsu_t(dsu_t&& other) noexcept : base(std::move(other)) {}
dsu_t& operator=(dsu_t&& other) noexcept {
CONSTEXPR_VECTOR dsu_t(dsu_t&& other) noexcept : base(std::move(other)) {}
CONSTEXPR_VECTOR dsu_t& operator=(dsu_t&& other) noexcept ATTRIBUTE_LIFETIME_BOUND {
base::operator=(std::move(other));
return *this;
}
constexpr void swap(dsu_t& other) noexcept {

CONSTEXPR_VECTOR void swap(dsu_t& other) noexcept {
base::swap(other);
}
friend constexpr void swap(dsu_t& lhs, dsu_t& rhs) noexcept {
friend CONSTEXPR_VECTOR void swap(dsu_t& lhs, dsu_t& rhs) noexcept {
lhs.swap(rhs);
}

// O(log*(n)) = O(a(n))
constexpr bool equal(size_type node_x_index, size_type node_y_index) noexcept {
[[nodiscard]] CONSTEXPR_VECTOR bool equal(size_type node_x_index,
size_type node_y_index) noexcept {
assert(node_x_index < size() && node_y_index < size());
return base::equal(node_x_index, node_y_index);
}
// O(log*(n)) = O(a(n))
constexpr void unite(size_type node_x_index, size_type node_y_index) noexcept {
CONSTEXPR_VECTOR void unite(size_type node_x_index, size_type node_y_index) noexcept {
assert(node_x_index < size() && node_y_index < size());
node_t* node_x_root_ptr = findRoot(node_x_index);
node_t* node_y_root_ptr = findRoot(node_y_index);
node_t* node_x_root_ptr = base::find_root(node_x_index);
node_t* node_y_root_ptr = base::find_root(node_y_index);
if (node_x_root_ptr == node_y_root_ptr) {
// Do not unite already united nodes so that for each root node:
// root_node->parent_ == nullptr
Expand All @@ -195,6 +213,9 @@ class dsu_t final : public dsu_impl::dsu_base<dsu_impl::dsu_node_t> {
}
}
}

private:
explicit CONSTEXPR_VECTOR dsu_t(size_type nodes_count) : base(nodes_count) {}
};

/// @brief See also class dsu_t and
Expand All @@ -206,16 +227,20 @@ class weighted_dsu_t final : public dsu_impl::dsu_base<dsu_impl::wdsu_node_t> {
weighted_dsu_t() = delete;

// O(n)
explicit weighted_dsu_t(size_type nodes_count) : base(nodes_count) {}
[[nodiscard]]
static CONSTEXPR_VECTOR weighted_dsu_t with_nodes_count(size_type nodes_count) {
return weighted_dsu_t{nodes_count};
}

using WeightsVec = std::vector<dsu_impl::Weight>;
// O(n)
explicit weighted_dsu_t(const std::vector<std::int64_t>& weights) : base(weights.size()) {
for (node_t* nodes_iter = data(); const auto weight : weights) {
nodes_iter->weight_ = weight;
++nodes_iter;
}
[[nodiscard]]
static CONSTEXPR_VECTOR weighted_dsu_t from_weights_vec(const WeightsVec& weights) {
return weighted_dsu_t{weights};
}

// O(n)
constexpr weighted_dsu_t(const weighted_dsu_t& other) : base(other) {
CONSTEXPR_VECTOR weighted_dsu_t(const weighted_dsu_t& other) : base(other) {
node_t* const this_first_node = data();
const node_t* const other_first_node = other.data();

Expand All @@ -229,31 +254,34 @@ class weighted_dsu_t final : public dsu_impl::dsu_base<dsu_impl::wdsu_node_t> {
}
}
// O(n)
constexpr weighted_dsu_t& operator=(const weighted_dsu_t& other) {
CONSTEXPR_VECTOR weighted_dsu_t& operator=(const weighted_dsu_t& other)
ATTRIBUTE_LIFETIME_BOUND {
return *this = weighted_dsu_t(other);
}
constexpr weighted_dsu_t(weighted_dsu_t&& other) noexcept : base(std::move(other)) {}
constexpr weighted_dsu_t& operator=(weighted_dsu_t&& other) noexcept {
CONSTEXPR_VECTOR weighted_dsu_t(weighted_dsu_t&& other) noexcept : base(std::move(other)) {}
CONSTEXPR_VECTOR weighted_dsu_t& operator=(weighted_dsu_t&& other) noexcept {
base::operator=(std::move(other));
return *this;
}
constexpr void swap(weighted_dsu_t& other) noexcept {

CONSTEXPR_VECTOR void swap(weighted_dsu_t& other) noexcept {
base::swap(other);
}
friend constexpr void swap(weighted_dsu_t& lhs, weighted_dsu_t& rhs) noexcept {
friend CONSTEXPR_VECTOR void swap(weighted_dsu_t& lhs, weighted_dsu_t& rhs) noexcept {
lhs.swap(rhs);
}

// O(log*(n))
constexpr bool equal(size_type node_x_index, size_type node_y_index) noexcept {
[[nodiscard]] CONSTEXPR_VECTOR bool equal(size_type node_x_index,
size_type node_y_index) noexcept {
assert(node_x_index < size() && node_y_index < size());
return base::equal(node_x_index, node_y_index);
}
// O(log*(n))
constexpr void unite(size_type node_x_index, size_type node_y_index) noexcept {
CONSTEXPR_VECTOR void unite(size_type node_x_index, size_type node_y_index) noexcept {
assert(node_x_index < size() && node_y_index < size());
node_t* node_x_root_ptr = findRoot(node_x_index);
node_t* node_y_root_ptr = findRoot(node_y_index);
node_t* node_x_root_ptr = base::find_root(node_x_index);
node_t* node_y_root_ptr = base::find_root(node_y_index);
if (node_x_root_ptr == node_y_root_ptr) {
// Do not unite already united nodes so that for each root node:
// root_node->parent_ == nullptr
Expand All @@ -278,20 +306,31 @@ class weighted_dsu_t final : public dsu_impl::dsu_base<dsu_impl::wdsu_node_t> {
}

// O(log*(n))
constexpr int64_t getWeightInSet(size_type node_index) noexcept {
[[nodiscard]] CONSTEXPR_VECTOR int64_t get_weight_is_set(size_type node_index) noexcept {
assert(node_index < size());
return findRoot(node_index)->weight_;
return base::find_root(node_index)->weight_;
}

// O(log*(n))
constexpr void addWeightInSet(size_type node_index, int64_t delta) noexcept {
CONSTEXPR_VECTOR void add_weight_in_set(size_type node_index, int64_t delta) noexcept {
assert(node_index < size());
findRoot(node_index)->weight_ += delta;
base::find_root(node_index)->weight_ += delta;
}

// O(log*(n))
constexpr void setWeightInSet(size_type node_index, int64_t weight) noexcept {
CONSTEXPR_VECTOR void set_weight_in_set(size_type node_index, int64_t weight) noexcept {
assert(node_index < size());
findRoot(node_index)->weight_ = weight;
base::find_root(node_index)->weight_ = weight;
}

private:
explicit CONSTEXPR_VECTOR weighted_dsu_t(size_type nodes_count) : base(nodes_count) {}

explicit CONSTEXPR_VECTOR weighted_dsu_t(const WeightsVec& weights) : base(weights.size()) {
node_t* nodes_iter = data();
for (const dsu_impl::Weight weight : weights) {
nodes_iter->weight_ = weight;
++nodes_iter;
}
}
};
Loading

0 comments on commit 80f05a4

Please sign in to comment.