diff --git a/src/pch.hpp b/src/pch.hpp index 84d07897ba1..ab57f178e84 100644 --- a/src/pch.hpp +++ b/src/pch.hpp @@ -18,6 +18,7 @@ #include "utils/definitions.hpp" #include "utils/simd.hpp" #include "utils/vectorset.hpp" +#include "utils/arraylist.hpp" #include "utils/vectorsort.hpp" // -------------------- diff --git a/src/utils/arraylist.hpp b/src/utils/arraylist.hpp new file mode 100644 index 00000000000..ea803ab8cf0 --- /dev/null +++ b/src/utils/arraylist.hpp @@ -0,0 +1,158 @@ +/** + * Canary - A free and open-source MMORPG server emulator + * Copyright (©) 2019-2022 OpenTibiaBR + * Repository: https://github.com/opentibiabr/canary + * License: https://github.com/opentibiabr/canary/blob/main/LICENSE + * Contributors: https://github.com/opentibiabr/canary/graphs/contributors + * Website: https://docs.opentibiabr.com/ + */ + +#pragma once + +#include +#include + +// # Mehah +// Arraylist is a very fast container for adding to the front and back, +// it uses two vectors to do this juggling and doesn't allow you to remove the front, as it is slow, +// use std::list for this case. + +namespace stdext { + template + class arraylist { + public: + bool contains(const T &v) { + update(); + return std::ranges::find(backContainer, v) != backContainer.end(); + } + + bool erase(const T &v) { + update(); + + const auto &it = std::ranges::find(backContainer, v); + if (it == backContainer.end()) { + return false; + } + backContainer.erase(it); + + return true; + } + + bool erase(const size_t begin, const size_t end) { + update(); + + if (begin > size() || end > size()) { + return false; + } + + backContainer.erase(backContainer.begin() + begin, backContainer.begin() + end); + return true; + } + + template + bool erase_if(F fnc) { + update(); + return std::erase_if(backContainer, std::move(fnc)) > 0; + } + + auto &front() { + update(); + return backContainer.front(); + } + + void pop_back() { + update(); + backContainer.pop_back(); + } + + auto &back() { + update(); + return backContainer.back(); + } + + void push_front(const T &v) { + needUpdate = true; + frontContainer.push_back(v); + } + + void push_front(T &&_Val) { + needUpdate = true; + frontContainer.push_back(std::move(_Val)); + } + + template + decltype(auto) emplace_front(_Valty &&... v) { + needUpdate = true; + return frontContainer.emplace_back(std::forward<_Valty>(v)...); + } + + void push_back(const T &v) { + backContainer.push_back(v); + } + + void push_back(T &&_Val) { + backContainer.push_back(std::move(_Val)); + } + + template + decltype(auto) emplace_back(_Valty &&... v) { + return backContainer.emplace_back(std::forward<_Valty>(v)...); + } + + bool empty() const noexcept { + return backContainer.empty() && frontContainer.empty(); + } + + size_t size() const noexcept { + return backContainer.size() + frontContainer.size(); + } + + auto begin() noexcept { + update(); + return backContainer.begin(); + } + + auto end() noexcept { + return backContainer.end(); + } + + void clear() noexcept { + frontContainer.clear(); + return backContainer.clear(); + } + + void reserve(size_t newCap) noexcept { + backContainer.reserve(newCap); + frontContainer.reserve(newCap); + } + + const auto &data() noexcept { + update(); + return backContainer.data(); + } + + T &operator[](const size_t i) { + update(); + return backContainer[i]; + } + + private: + inline void update() noexcept { + if (!needUpdate) { + return; + } + + needUpdate = false; + std::ranges::reverse(frontContainer); + frontContainer.insert(frontContainer.end(), make_move_iterator(backContainer.begin()), make_move_iterator(backContainer.end())); + backContainer.clear(); + backContainer.insert(backContainer.end(), make_move_iterator(frontContainer.begin()), make_move_iterator(frontContainer.end())); + frontContainer.clear(); + } + + std::vector backContainer; + std::vector frontContainer; + + bool needUpdate = false; + }; +} diff --git a/vcproj/canary.vcxproj b/vcproj/canary.vcxproj index ed1217302f2..7b467346d39 100644 --- a/vcproj/canary.vcxproj +++ b/vcproj/canary.vcxproj @@ -212,6 +212,7 @@ +