Commit d58bd7ff authored by Gauthier Quesnel's avatar Gauthier Quesnel
Browse files

add links

parent 3910cd13
#include <bits/assert.hpp>
#include <vector>
namespace bits {
template<typename Identifier, typename Allocator = std::allocator<Identifier>>
class links
{
private:
std::vector<value_type, Allocator> items;
public:
using container_type = std::vector<value_type, Allocator>;
using value_type = container_type::value_type;
using reference = container_type::reference;
public:
links(const size_t size, const Allocator& allocator)
: items(size, -1, allocator)
{
bits_expects(size > 0);
}
Identifier operator[](const Identifier ID) const noexcept
{
bits_expects(bits::valid(ID));
return items[bits::get_index(ID)];
}
Identifier& operator[](const Identifier ID) noexcept
{
bits_assert(bits::valid(ID));
return items[bits::get_index(ID)];
}
void destroy(const Identifier ID) noexcept
{
bits_assert(bits::valid(ID));
items[bits::get_index(ID)] = { -1 };
}
};
template<typename List, typename DataArray, typename Identifier>
class multi_links_iterator
{
public:
using iterator_category = std::forward_iterator_tag;
using value_type = Identifier;
using difference_type = std::ptrdiff_t;
using pointer = Identifier*;
using reference = Identifier&;
private:
List* list = nullptr;
DataArray* dataarray = nullptr;
Identifier elem = { -1 };
public:
multi_links_iterator() noexcept = default;
multi_links_iterator(const multi_links_iterator&) noexcept = default;
multi_links_iterator& operator=(const multi_links_iterator&) noexcept =
default;
multi_links_iterator(List* list_,
DataArray* dataarray_,
Identifier elem_) noexcept
: list(list_)
, dataarray(dataarray_)
, elem(elem_)
{}
multi_links_iterator(multi_links_iterator&& other) noexcept
: list(other.list)
, dataarray_(other.dataarray)
, elem(other.elem)
{
other.list = nullptr;
other.dataarray = nullptr;
other.elem = -1;
}
multi_links_iterator& operator=(multi_links_iterator&& other) noexcept
{
if (this != &other) {
list = other.list;
dataarray = other.dataarray;
elem = other.elem;
other.list = nullptr;
other.dataarray = nullptr;
other.elem = { -1 };
}
return *this;
}
/**
* @brief Advance the ID to the next valid ID in the linked list.
*
* @details If a element is invalid, this element is removed from the list.
*/
void advance() noexcept
{
if (list && elem >= 0) {
int next = list[elem].next;
while (next >= 0) {
if (dataarray->try_to_get(list[next].id)) {
elem = next;
return;
} else {
list[elem].next = list[next].next;
list[next].next = free_head;
free_head = next;
next = list[elem].next;
}
}
}
}
iterator operator++(int)
{
iterator copy(*this);
advance();
return copy;
}
iterator operator++()
{
advance();
return *this;
}
pointer operator->() const noexcept
{
return &list[elem].id;
}
reference operator*() const noexcept
{
return list[elem].id;
}
friend void swap(iterator& lhs, iterator& rhs) noexcept
{
auto items_ = lhs.items;
auto id_ = lhs.id;
lhs.items = rhs.items;
lhs.id = rhs.id;
rhs.items = items_;
rhs.id = id_;
}
friend bool operator==(const iterator& lhs, const iterator& rhs) noexcept
{
return lhs.id == rhs.id;
}
friend bool operator!=(const iterator& lhs, const iterator& rhs) noexcept
{
return !(lhs.id == rhs.id);
}
};
template <typename Identifier>
struct multi_links_node
{
Identifier id = { -1 };
int next = { -1 };
};
template<typename Identifier,
typename IdentifierAllocator = std::allocator<Identifier>,
typename NodeAllocator = std::allocator<mult_links_node>>
class multi_links
{
private:
std::vector<int, IdentifierAllocator> map; // Map ID to head in the linked list.
std::vector<mult_links_node, NodeAllocator> list; // The linked list.
int free_head = -1;
public:
multi_links(int size, const Allocator& allocator) noexcept
: map(size, -1, allocator)
, list(size, allocator)
, free_head(-1)
{
list.clear();
}
void emplace(Identifier ID, Identifier value) noexcept
{
assert(bits::valid(ID));
assert(bits::valid(value));
auto index = bits::get_index(ID);
int new_pos;
if (free_head < 0) {
list.emplace_back(value, -1);
new_pos = static_cast<int>(list.size());
} else {
list[free_head].id = value;
new_pos = free_head;
free_head = list[free_head].next;
}
list[new_pos].next = map[index];
map[index] = new_pos;
}
iterator begin(Identifier head) noexcept
{
auto index = bits::get_index(ID);
return iterator(&list, index);
}
iterator end() noexcept
{
return iterator(&list, -1);
}
void destroy(Identifier ID)
{
assert(bits::valid(ID));
auto index = bits::get_index(ID);
auto id = map[index];
map[index] = -1;
while (id >= 0) {
auto to_delete = id;
index = list[id].next;
list[to_delete].id = -1;
list[to_delete].next = free_head;
free_head = to_delete;
}
}
};
} // namespace bits
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