File: multitree_impl.hpp

package info (click to toggle)
iqtree 2.0.7%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 14,620 kB
  • sloc: cpp: 142,571; ansic: 57,789; sh: 275; python: 242; makefile: 95
file content (145 lines) | stat: -rw-r--r-- 3,926 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#ifndef MULTITREE_IMPL_HPP
#define MULTITREE_IMPL_HPP

#include "multitree.hpp"

#include <memory>

namespace terraces {
namespace multitree_impl {

template <typename T>
struct array_deleter {
	void operator()(T* ptr) { delete[] ptr; }
};

template <typename T>
std::unique_ptr<T[], array_deleter<T>> make_unique_array(std::size_t size) {
	// this may leak memory if allocation or construction of a T fails
	return std::unique_ptr<T[], array_deleter<T>>{new T[size]};
}

template <typename T>
class storage_block {
private:
	std::unique_ptr<T[], array_deleter<T>> begin;
	index size;
	index max_size;

public:
	storage_block(index max_size)
	        : begin{make_unique_array<T>(max_size)}, size{0}, max_size{max_size} {}

	bool has_space(index required = 1) { return size + required <= max_size; }

	T* get() {
		assert(has_space());
		return begin.get() + (size++);
	}

	T* get_range(index required) {
		assert(has_space(required));
		auto result = begin.get() + size;
		size += required;
		return result;
	}
};

template <typename T>
class storage_blocks {
private:
	std::vector<storage_block<T>> m_blocks;
	index m_block_size;

public:
	storage_blocks(index block_size = 1024) : m_blocks{}, m_block_size{block_size} {
		m_blocks.emplace_back(m_block_size);
	}
	storage_blocks(const storage_blocks<T>& other) : storage_blocks{other.m_block_size} {}
	storage_blocks(storage_blocks<T>&& other) = default;
	storage_blocks<T>& operator=(const storage_blocks<T>& other) {
		m_block_size = other.m_block_size;
		return *this;
	}
	storage_blocks<T>& operator=(storage_blocks<T>&& other) = default;

	T* get() {
		if (!m_blocks.back().has_space()) {
			m_blocks.emplace_back(m_block_size);
		}
		return m_blocks.back().get();
	}

	T* get_range(index required) {
		if (!m_blocks.back().has_space(required)) {
			m_blocks.emplace_back(required);
			auto result = m_blocks.back().get_range(required);
			auto last_it = --m_blocks.end();
			auto prev_it = --(--m_blocks.end());
			std::iter_swap(
			        last_it,
			        prev_it); // TODO this might lead to some bad worst-case behaviour
			return result;
		}
		return m_blocks.back().get_range(required);
	}
};

inline multitree_node* make_single_leaf(multitree_node* n, index i) {
	n->type = multitree_node_type::base_single_leaf;
	n->single_leaf = i;
	n->num_leaves = 1;
	n->num_trees = 1;
	return n;
}

inline multitree_node* make_two_leaves(multitree_node* n, index i, index j) {
	n->type = multitree_node_type::base_two_leaves;
	n->two_leaves = {i, j};
	n->num_leaves = 2;
	n->num_trees = 1;
	return n;
}

inline multitree_node* make_unconstrained(multitree_node* n, std::pair<index*, index*> range) {
	auto begin = range.first;
	auto end = range.second;
	n->type = multitree_node_type::base_unconstrained;
	n->unconstrained = {begin, end};
	n->num_leaves = (index)(end - begin);
	n->num_trees = count_unrooted_trees<index>(n->num_leaves);
	return n;
}

inline multitree_node* make_inner_node(multitree_node* n, multitree_node* left,
                                       multitree_node* right) {
	n->type = multitree_node_type::inner_node;
	n->inner_node = {left, right};
	n->num_leaves = left->num_leaves + right->num_leaves;
	n->num_trees = left->num_trees * right->num_trees;
	return n;
}

inline multitree_node* make_alternative_array(multitree_node* n, multitree_node* begin,
                                              index leaves) {
	n->type = multitree_node_type::alternative_array;
	n->alternative_array = {begin, begin};
	n->num_leaves = leaves;
	n->num_trees = 0;
	return n;
}

inline multitree_node* make_unexplored(multitree_node* n, std::pair<index*, index*> range) {
	auto begin = range.first;
	auto end = range.second;
	n->type = multitree_node_type::unexplored;
	n->unexplored = {begin, end};
	n->num_leaves = (index)(end - begin);
	n->num_trees = 0;
	return n;
}

} // namespace multitree_impl
} // namespace terraces

#endif // MULTITREE_IMPL_HPP