Last active
June 4, 2019 10:10
-
-
Save scaryghost/09a3b12fc43bb09f19216bca9534105e to your computer and use it in GitHub Desktop.
Nonhomogeneous list that stores its elements sequentially
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "generic_list.hpp" | |
#include <algorithm> | |
#include <cstdlib> | |
using std::for_each; | |
using std::free; | |
using std::malloc; | |
using std::memcpy; | |
using std::memmove; | |
using std::uint8_t; | |
using std::unordered_map; | |
GenericList::GenericList() : | |
elements(nullptr, [](uint8_t* ptr) { | |
free(ptr); | |
}), | |
offsets({0}), | |
capacity(0) { | |
} | |
GenericList::GenericList(size_t capacity) : GenericList() { | |
resize(capacity); | |
} | |
GenericList::~GenericList() { | |
for(auto &it: deallocators) { | |
it.second(elements.get() + offsets[it.first]); | |
} | |
elements.release(); | |
offsets.clear(); | |
deallocators.clear(); | |
} | |
size_t GenericList::size() const { | |
return offsets.size() - 1; | |
} | |
void GenericList::resize(size_t capacity) { | |
auto ptr = (uint8_t*) malloc(capacity); | |
memcpy(ptr, elements.get(), this->capacity); | |
elements.reset(ptr); | |
this->capacity = capacity; | |
} | |
void* GenericList::operator[](size_t i) const { | |
return elements.get() + offsets[i]; | |
} | |
void GenericList::remove(size_t i) { | |
if (deallocators.count(i)) { | |
deallocators.at(i)(elements.get() + offsets[i]); | |
deallocators.erase(i); | |
unordered_map<size_t, void(*)(void*)> updated_deallocators; | |
for_each(deallocators.begin(), deallocators.end(), [&updated_deallocators, i](auto const& e) { | |
if (e.first < (i + 1)) { | |
updated_deallocators.insert({ e.first, e.second }); | |
} else { | |
updated_deallocators.insert({ e.first - 1, e.second }); | |
} | |
}); | |
deallocators = updated_deallocators; | |
} | |
if (i < offsets.size() - 1) { | |
auto size = offsets[i + 1] - offsets[i]; | |
memmove(elements.get() + offsets[i], elements.get() + offsets[i + 1], occupied() - size); | |
offsets.erase(offsets.begin() + (i + 1)); | |
for_each(offsets.begin() + (i + 1), offsets.end(), [size](size_t& e) { | |
e -= size; | |
}); | |
} else { | |
offsets.erase(offsets.begin() + i); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <cstdint> | |
#include <cstring> | |
#include <memory> | |
#include <vector> | |
#include <unordered_map> | |
#include <utility> | |
class GenericList { | |
public: | |
GenericList(); | |
GenericList(size_t capacity); | |
~GenericList(); | |
template <typename T> | |
void add(const T& value, void(*deallocator)(void*)=nullptr); | |
template <typename T> | |
void add(T&& value, void(*deallocator)(void*)=nullptr); | |
void remove(size_t i); | |
void resize(size_t capacity); | |
template <typename T> | |
T& operator[] (size_t i) const; | |
void* operator[](size_t i) const; | |
size_t size() const; | |
private: | |
inline size_t occupied() const { | |
return offsets.back(); | |
} | |
std::unique_ptr<std::uint8_t, void(*)(std::uint8_t*)> elements; | |
std::vector<size_t> offsets; | |
std::unordered_map<size_t, void(*)(void*)> deallocators; | |
std::size_t capacity; | |
}; | |
template <typename T> | |
void GenericList::add(const T& value, void(*deallocator)(void*)) { | |
auto target_capacity = sizeof(T) + occupied(); | |
if (target_capacity > capacity) { | |
resize(target_capacity * 2); | |
} | |
auto ptr = (T*)(elements.get() + occupied()); | |
*ptr = value; | |
offsets.push_back(target_capacity); | |
if (deallocator != nullptr) { | |
deallocators.insert({size() - 1, deallocator}); | |
} | |
} | |
template <typename T> | |
void GenericList::add(T&& value, void(*deallocator)(void*)) { | |
auto target_capacity = sizeof(T) + occupied(); | |
if (target_capacity > capacity) { | |
resize(target_capacity * 2); | |
} | |
auto ptr = (T*)(elements.get() + occupied()); | |
std::swap(*ptr, value); | |
offsets.push_back(target_capacity); | |
if (deallocator != nullptr) { | |
deallocators.insert({size() - 1, deallocator}); | |
} | |
} | |
template <typename T> | |
T& GenericList::operator[] (size_t i) const { | |
return *((T*) (elements.get() + offsets[i])); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment