/*
 * Copyright 2015 - 2025 gary@drinkingtea.net
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

#pragma once

#include "array.hpp"
#include "concepts.hpp"
#include "bit.hpp"
#include "error.hpp"
#include "initializerlist.hpp"
#include "iterator.hpp"
#include "math.hpp"
#include "memory.hpp"
#include "stringview.hpp"
#include "types.hpp"
#include "utility.hpp"

OX_ALLOW_UNSAFE_BUFFERS_BEGIN

namespace ox {

namespace detail {

template<typename T, typename Allocator, size_t Size = 1>
struct VectorAllocator {
	static_assert(sizeof(AllocAlias<T>) == sizeof(T));
	static_assert(alignof(AllocAlias<T>) == alignof(T));
	private:
		ox::Array<AllocAlias<T>, Size> m_data = {};
	protected:
		constexpr VectorAllocator() noexcept = default;
		constexpr VectorAllocator(VectorAllocator const&) noexcept = default;
		constexpr VectorAllocator(VectorAllocator&&) noexcept = default;

		constexpr void allocate(T **items, size_t const cap) noexcept {
			// small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr
			if (std::is_constant_evaluated() || cap > Size) {
				*items = Allocator{}.allocate(cap);
			} else {
				*items = reinterpret_cast<T*>(m_data.data());
			}
		}

		constexpr void moveConstructItemsFrom(
				T **items,
				VectorAllocator *src,
				size_t const count,
				size_t const cap) noexcept {
			// this totally idiotic redundant check (&& count <= Size) is required to address a bug in devkitARM,
			// try removing it later
			if (!std::is_constant_evaluated()) {
#if defined(__GNUC__) && !defined(__clang__)
	#pragma GCC diagnostic push
	#pragma GCC diagnostic ignored "-Wstringop-overflow="
#endif
				if (cap <= m_data.size() && count <= m_data.size()) {
					for (auto i = 0u; i < count; ++i) {
						auto const srcItem = std::launder(reinterpret_cast<T*>(&src->m_data[i]));
#if defined(__GNUC__) && __GNUC__ >= 12
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-overflow="
#endif
						new (&m_data[i]) T(std::move(*srcItem));
#if defined(__GNUC__) && __GNUC__ >= 12
#pragma GCC diagnostic pop
#endif
					}
					if (count) {
						*items = std::launder(reinterpret_cast<T*>(m_data.data()));
					} else {
						*items = reinterpret_cast<T*>(m_data.data());
					}
				}
#if defined(__GNUC__) && !defined(__clang__)
	#pragma GCC diagnostic pop
#endif
			}
		}

		constexpr void deallocate(T *const items, size_t const cap) noexcept {
			// small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr
			if (std::is_constant_evaluated()) {
				if (items) {
					Allocator{}.deallocate(items, cap);
				}
			} else {
				if (items && static_cast<void*>(items) != static_cast<void*>(m_data.data())) {
					Allocator{}.deallocate(items, cap);
				}
			}
		}

};

template<typename T, typename Allocator>
struct VectorAllocator<T, Allocator, 0> {
	protected:
		constexpr VectorAllocator() noexcept = default;
		constexpr VectorAllocator(VectorAllocator const&) noexcept = default;
		constexpr VectorAllocator(VectorAllocator&&) noexcept = default;

		constexpr void allocate(T **items, size_t const cap) noexcept {
			*items = Allocator{}.allocate(cap);
		}

		[[maybe_unused]]
		constexpr void moveConstructItemsFrom(
				T**,
				VectorAllocator*,
				size_t const,
				size_t const) noexcept {
		}

		[[maybe_unused]]
		constexpr void moveItemsFrom(T**, VectorAllocator*, size_t const, size_t const) noexcept {
		}

		constexpr void deallocate(T *const items, size_t const cap) noexcept {
			if (items) {
				Allocator{}.deallocate(items, cap);
			}
		}

};

}

template<typename T, size_t SmallVectorSize = 0, typename Allocator = std::allocator<T>>
class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {

	public:
		using value_type = T;
		using size_type = size_t;

		template<typename RefType = T&, typename PtrType = T*, bool reverse = false>
		using iterator = SpanIterator<T, RefType, PtrType, reverse>;

	private:
		static constexpr auto initialCap = SmallVectorSize > 0 ? SmallVectorSize : 50;
		static constexpr auto useNoexcept = ox::is_integral_v<T> || ox::is_pointer_v<T>;
		size_t m_size = 0;
		size_t m_cap = 0;
		T *m_items = nullptr;

	public:
		constexpr Vector() noexcept = default;

		explicit constexpr Vector(size_t size) noexcept;

		constexpr Vector(std::initializer_list<T> list) noexcept;

		constexpr Vector(Vector const &other) noexcept(useNoexcept);

		constexpr Vector(Vector &&other) noexcept;

		constexpr ~Vector();

		constexpr iterator<> begin() noexcept {
			return iterator<>(m_items, 0, m_size);
		}

		constexpr iterator<> end() noexcept {
			return iterator<>(m_items, m_size, m_size);
		}

		[[nodiscard]]
		constexpr iterator<T const&, T const*> begin() const noexcept {
			return iterator<T const&, T const*>(m_items, 0, m_size);
		}

		[[nodiscard]]
		constexpr iterator<T const&, T const*> end() const noexcept {
			return iterator<T const&, T const*>(m_items, m_size, m_size);
		}

		[[nodiscard]]
		constexpr iterator<T const&, T const*> cbegin() const noexcept {
			return iterator<T const&, T const*>(m_items, 0, m_size);
		}

		[[nodiscard]]
		constexpr iterator<T const&, T const*> cend() const noexcept {
			return iterator<T const&, T const*>(m_items, m_size, m_size);
		}

		[[nodiscard]]
		constexpr iterator<T&, T*, true> rbegin() noexcept {
			return iterator<T&, T*, true>(m_items, m_size - 1, m_size);
		}

		[[nodiscard]]
		constexpr iterator<T&, T*, true> rend() noexcept {
			return iterator<T&, T*, true>(m_items, MaxValue<size_type>, m_size);
		}

		[[nodiscard]]
		constexpr iterator<T const&, T const*, true> crbegin() const noexcept {
			return iterator<T const&, T const*, true>(m_items, m_size - 1, m_size);
		}

		[[nodiscard]]
		constexpr iterator<T const&, T const*, true> crend() const noexcept {
			return iterator<T const&, T const*, true>(m_items, MaxValue<size_type>, m_size);
		}

		[[nodiscard]]
		constexpr iterator<T const&, T const*, true> rbegin() const noexcept {
			return iterator<T const&, T const*, true>(m_items, m_size - 1, m_size);
		}

		[[nodiscard]]
		constexpr iterator<T const&, T const*, true> rend() const noexcept {
			return iterator<T const&, T const*, true>(m_items, MaxValue<size_type>, m_size);
		}

		constexpr bool operator==(Vector const &other) const noexcept(useNoexcept);

		constexpr Vector &operator=(Vector const &other) noexcept(useNoexcept);

		constexpr Vector &operator=(Vector &&other) noexcept;

		[[nodiscard]]
		constexpr T &operator[](size_t i) noexcept;

		[[nodiscard]]
		constexpr T const &operator[](size_t i) const noexcept;

		[[nodiscard]]
		constexpr Result<T*> at(size_t i) noexcept;

		[[nodiscard]]
		constexpr Result<T const*> at(size_t i) const noexcept;

		[[nodiscard]]
		constexpr Result<T*> front() noexcept;

		[[nodiscard]]
		constexpr Result<T const*> front() const noexcept;

		[[nodiscard]]
		constexpr Result<T*> back() noexcept;

		[[nodiscard]]
		constexpr Result<T const*> back() const noexcept;

		[[nodiscard]]
		constexpr size_t capacity() const noexcept;

		[[nodiscard]]
		constexpr size_t size() const noexcept;

		[[nodiscard]]
		constexpr bool empty() const noexcept;

		constexpr void clear() noexcept(useNoexcept);

		constexpr void resize(size_t size) noexcept(useNoexcept);

		constexpr void reserveResize(size_t size) noexcept(useNoexcept);

		[[nodiscard]]
		constexpr T *data() noexcept {
			return m_items;
		}

		[[nodiscard]]
		constexpr T const *data() const noexcept {
			return m_items;
		}

		[[nodiscard]]
		constexpr bool contains(MaybeView_t<T> const&) const noexcept;

		constexpr iterator<T&, T*, false> insert(
			size_t pos, size_t cnt, T const &val) noexcept(useNoexcept);

		constexpr iterator<T&, T*, false> insert(size_t pos, T val) noexcept(useNoexcept);

		template<typename... Args>
		constexpr iterator<T&, T*, false> emplace(size_t pos, Args&&... args) noexcept(useNoexcept);

		template<typename... Args>
		constexpr T &emplace_back(Args&&... args) noexcept(useNoexcept);

		constexpr void push_back(T const &item) noexcept(useNoexcept);

		constexpr void push_back(T &&item) noexcept(useNoexcept);

		constexpr void pop_back() noexcept(useNoexcept);

		/**
		 * Removes an item from the Vector.
		 * @param pos iterator at the point to remove
		 * @return Error if index is out of bounds
		 */
		constexpr Result<iterator<T&, T*, false>> erase(iterator<> const &pos) noexcept(useNoexcept);

		/**
		 * Removes an item from the Vector.
		 * @param pos position of item to remove
		 * @return Error if index is out of bounds
		 */
		constexpr Result<iterator<T&, T*, false>> erase(size_t pos) noexcept(useNoexcept);

		/**
		 * Moves the last item in the Vector to position pos and decrements the
		 * size by 1.
		 * @param pos position of item to remove
		 * @return Error if index is out of bounds
		 */
		constexpr Error unordered_erase(size_t pos) noexcept(useNoexcept);

		constexpr Error remove(MaybeView_t<T> const &val);

		constexpr void reserve(size_t cap) noexcept(useNoexcept);

		constexpr void shrink_to_fit() noexcept(useNoexcept);

	private:
		constexpr void reserveInsert(
				size_t cap, size_t pos, size_t offset = 1) noexcept(useNoexcept);

};

template<typename T, size_t SmallVectorSize, typename Allocator, typename RefType, bool reverse>
using VectorIt = typename Vector<T, SmallVectorSize, Allocator>::template iterator<RefType, reverse>;

template<typename T, size_t SmallVectorSize, typename Allocator, typename RefType, bool reverse>
constexpr VectorIt<T, SmallVectorSize, Allocator, RefType, reverse> operator+(
		size_t n,
		VectorIt<T, SmallVectorSize, Allocator, RefType, reverse> const &a) {
	return a + n;
}

template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr Vector<T, SmallVectorSize, Allocator>::Vector(size_t const size) noexcept {
	m_size = size;
	m_cap = m_size;
	this->allocate(&m_items, m_cap);
	for (size_t i = 0; i < size; ++i) {
		std::construct_at(&m_items[i]);
	}
}

template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr Vector<T, SmallVectorSize, Allocator>::Vector(std::initializer_list<T> list) noexcept {
	m_size = list.size();
	m_cap = m_size;
	this->allocate(&m_items, m_cap);
	for (size_t i{}; auto &item : list) {
		std::construct_at(&m_items[i], std::move(item));
		++i;
	}
}

template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr Vector<T, SmallVectorSize, Allocator>::Vector(Vector const &other) noexcept(useNoexcept) {
	m_size = other.m_size;
	m_cap = other.m_cap;
	this->allocate(&m_items, other.m_cap);
	for (size_t i = 0; i < m_size; ++i) {
		std::construct_at(&m_items[i], other.m_items[i]);
	}
}

template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr Vector<T, SmallVectorSize, Allocator>::Vector(Vector &&other) noexcept {
	m_size = other.m_size;
	m_cap = other.m_cap;
	m_items = other.m_items;
	this->moveConstructItemsFrom(&m_items, &other, m_size, m_cap);
	other.m_size = 0;
	other.m_cap = 0;
	other.m_items = nullptr;
}

template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr Vector<T, SmallVectorSize, Allocator>::~Vector() {
	clear();
	this->deallocate(m_items, m_cap);
	m_items = nullptr;
}

template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr bool Vector<T, SmallVectorSize, Allocator>::operator==(
		Vector const &other) const noexcept(useNoexcept) {
	if (m_size != other.m_size) {
		return false;
	}
	for (size_t i = 0; i < m_size; i++) {
		if (!(m_items[i] == other.m_items[i])) {
			return false;
		}
	}
	return true;
}

template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr Vector<T, SmallVectorSize, Allocator> &Vector<T, SmallVectorSize, Allocator>::operator=(
		Vector const &other) noexcept(useNoexcept) {
	if (this != &other) {
		clear();
		this->deallocate(m_items, m_cap);
		m_items = nullptr;
		m_size = other.m_size;
		m_cap = other.m_cap;
		this->allocate(&m_items, other.m_cap);
		for (size_t i = 0; i < m_size; i++) {
			std::construct_at(&m_items[i], other.m_items[i]);
		}
	}
	return *this;
}

template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr Vector<T, SmallVectorSize, Allocator> &Vector<T, SmallVectorSize, Allocator>::operator=(
		Vector &&other) noexcept {
	if (this != &other) {
		clear();
		this->deallocate(m_items, m_cap);
		m_size = other.m_size;
		m_cap = other.m_cap;
		m_items = other.m_items;
		this->moveConstructItemsFrom(&m_items, &other, m_size, m_cap);
		other.m_size = 0;
		other.m_cap = 0;
		other.m_items = nullptr;
	}
	return *this;
}

template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr T &Vector<T, SmallVectorSize, Allocator>::operator[](size_t const i) noexcept {
	boundsCheck(i, size(), "Vector access overflow");
	return m_items[i];
}

template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr T const &Vector<T, SmallVectorSize, Allocator>::operator[](size_t const i) const noexcept {
	boundsCheck(i, size(), "Vector access overflow");
	return m_items[i];
}

template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr Result<T*> Vector<T, SmallVectorSize, Allocator>::at(size_t const i) noexcept {
	if (i < size()) [[likely]] {
		return &operator[](i);
	}
	return ox::Error(1, "Vector: Invalid index");
}

template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr Result<T const*> Vector<T, SmallVectorSize, Allocator>::at(size_t const i) const noexcept {
	if (i < size()) [[likely]] {
		return &operator[](i);
	}
	return ox::Error(1, "Vector: Invalid index");
}

template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr Result<T*> Vector<T, SmallVectorSize, Allocator>::front() noexcept {
	if (!m_size) {
		return {nullptr, ox::Error(1)};
	}
	return &m_items[0];
}

template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr Result<T const*> Vector<T, SmallVectorSize, Allocator>::front() const noexcept {
	if (!m_size) {
		return {nullptr, ox::Error(1)};
	}
	return &m_items[0];
}

template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr Result<T*> Vector<T, SmallVectorSize, Allocator>::back() noexcept {
	if (!m_size) {
		return {nullptr, ox::Error(1)};
	}
	return &m_items[m_size - 1];
}

template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr Result<T const*> Vector<T, SmallVectorSize, Allocator>::back() const noexcept {
	if (!m_size) {
		return {nullptr, ox::Error(1)};
	}
	return &m_items[m_size - 1];
}

template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr size_t Vector<T, SmallVectorSize, Allocator>::capacity() const noexcept {
	return m_cap;
}

template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr size_t Vector<T, SmallVectorSize, Allocator>::size() const noexcept {
	return m_size;
}

template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr bool Vector<T, SmallVectorSize, Allocator>::empty() const noexcept {
	return !m_size;
}

template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::clear() noexcept(useNoexcept) {
	if constexpr(is_class<T>()) {
		for (size_t i = 0; i < m_size; ++i) {
			m_items[i].~T();
		}
	}
	m_size = 0;
}

template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::resize(size_t const size) noexcept(useNoexcept) {
	if (m_cap < size) {
		reserve(size * 2);
	}
	if (m_size < size) {
		for (size_t i = m_size; i < size; i++) {
			std::construct_at(&m_items[i]);
		}
	} else {
		for (size_t i = size; i < m_size; i++) {
			m_items[i].~T();
		}
	}
	m_size = size;
}

template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::reserveResize(size_t const size) noexcept(useNoexcept) {
	reserve(size);
	resize(size);
}

template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr bool Vector<T, SmallVectorSize, Allocator>::contains(MaybeView_t<T> const &v) const noexcept {
	for (size_t i = 0; i < m_size; ++i) {
		if (m_items[i] == v) {
			return true;
		}
	}
	return false;
}

template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false>
Vector<T, SmallVectorSize, Allocator>::insert(
	size_t const pos, size_t const cnt, T const &val) noexcept(useNoexcept) {
	if (m_size + cnt > m_cap) {
		reserveInsert(m_cap ? m_size + cnt : initialCap, pos, cnt);
	}
	if (pos < m_size) {
		for (auto i = m_size + cnt - 1; i > pos; --i) {
			std::construct_at(&m_items[i], std::move(m_items[i - cnt]));
		}
		for (auto i = pos; i < pos + cnt; ++i) {
			m_items[i] = val;
		}
	} else {
		for (auto i = 0u; i < cnt; ++i) {
			std::construct_at(&m_items[pos + i], m_items[pos]);
		}
	}
	m_size += cnt;
	return begin() + pos;
}

template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false>
Vector<T, SmallVectorSize, Allocator>::insert(size_t pos, T val) noexcept(useNoexcept) {
	if (m_size == m_cap) {
		reserveInsert(m_cap ? m_cap * 2 : initialCap, pos);
	}
	if (pos < m_size) {
		for (auto i = m_size; i > pos; --i) {
			std::construct_at(&m_items[i], std::move(m_items[i - 1]));
		}
		m_items[pos] = std::move(val);
	} else {
		std::construct_at(&m_items[pos], std::move(val));
	}
	++m_size;
	return begin() + pos;
}

template<typename T, size_t SmallVectorSize, typename Allocator>
template<typename... Args>
constexpr typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false>
Vector<T, SmallVectorSize, Allocator>::emplace(size_t pos, Args&&... args) noexcept(useNoexcept) {
	if (m_size == m_cap) {
		reserveInsert(m_cap ? m_cap * 2 : initialCap, pos);
		if (pos < m_size) {
			m_items[pos].~T();
		}
		std::construct_at(&m_items[pos], ox::forward<Args>(args)...);
	} else {
		if (pos < m_size) {
			for (auto i = m_size; i > pos; --i) {
				std::construct_at(&m_items[i], std::move(m_items[i - 1]));
			}
			m_items[pos].~T();
		}
		std::construct_at(&m_items[pos], ox::forward<Args>(args)...);
	}
	++m_size;
	return begin() + pos;
}

template<typename T, size_t SmallVectorSize, typename Allocator>
template<typename... Args>
constexpr T &Vector<T, SmallVectorSize, Allocator>::emplace_back(Args&&... args) noexcept(useNoexcept) {
	if (m_size == m_cap) {
		reserve(m_cap ? m_cap * 2 : initialCap);
	}
	auto out = std::construct_at(&m_items[m_size], ox::forward<Args>(args)...);
	++m_size;
	return *out;
}

template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(T const &item) noexcept(useNoexcept) {
	if (m_size == m_cap) {
		reserve(m_cap ? m_cap * 2 : initialCap);
	}
	std::construct_at(&m_items[m_size], item);
	++m_size;
}

template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(T &&item) noexcept(useNoexcept) {
	if (m_size == m_cap) {
		reserve(m_cap ? m_cap * 2 : initialCap);
	}
	std::construct_at(&m_items[m_size], std::move(item));
	++m_size;
}

template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::pop_back() noexcept(useNoexcept) {
	--m_size;
	m_items[m_size].~T();
}

template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr Result<typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false>>
Vector<T, SmallVectorSize, Allocator>::erase(iterator<> const &pos) noexcept(useNoexcept) {
	return erase(pos.offset());
}

template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr Result<typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false>>
Vector<T, SmallVectorSize, Allocator>::erase(size_t pos) noexcept(useNoexcept) {
	if (pos >= m_size) {
		return ox::Error(1, "Vector::erase failed: pos is greater than Vector size");
	}
	--m_size;
	for (auto i = pos; i < m_size; ++i) {
		m_items[i] = std::move(m_items[i + 1]);
	}
	m_items[m_size].~T();
	return begin() + pos;
}

template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr Error Vector<T, SmallVectorSize, Allocator>::unordered_erase(size_t pos)
	noexcept(useNoexcept) {
	if (pos >= m_size) {
		return ox::Error(1);
	}
	--m_size;
	m_items[pos] = std::move(m_items[m_size]);
	m_items[m_size].~T();
	return {};
}

template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr ox::Error Vector<T, SmallVectorSize, Allocator>::remove(MaybeView_t<T> const &val) {
	for (size_t i{}; auto const &v : *this) {
		if (v == val) {
			return erase(i).error;
		}
		++i;
	}
	return ox::Error{1, "element not found"};
}

template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::reserve(size_t cap) noexcept(useNoexcept) {
	if (cap <= m_cap) {
		return;
	}
	auto const oldItems = m_items;
	auto const oldCap = m_cap;
	m_cap = cap;
	this->allocate(&m_items, cap);
	if (oldItems) { // move over old items
		auto const itRange = ox::min(cap, m_size);
		for (size_t i = 0; i < itRange; ++i) {
			std::construct_at(&m_items[i], std::move(oldItems[i]));
			oldItems[i].~T();
		}
		this->deallocate(oldItems, oldCap);
	}
}

template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::shrink_to_fit() noexcept(useNoexcept)  {
	if (m_size == m_cap) {
		return;
	}
	auto const oldItems = m_items;
	auto const oldCap = m_cap;
	m_cap = m_size;
	this->allocate(&m_items, m_size);
	if (oldItems) { // move over old items
		for (size_t i = 0; i < m_size; ++i) {
			std::construct_at(&m_items[i], std::move(oldItems[i]));
			oldItems[i].~T();
		}
		this->deallocate(oldItems, oldCap);
	}
}

template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::reserveInsert(
		size_t cap,
		size_t pos,
		size_t offset) noexcept(useNoexcept) {
	if (cap <= m_cap) {
		return;
	}
	auto const oldItems = m_items;
	auto const oldCap = m_cap;
	m_cap = cap;
	this->allocate(&m_items, cap);
	if (oldItems) { // move over old items
		auto itRange = ox::min(m_size, pos);
		for (size_t i = 0; i < itRange; ++i) {
			std::construct_at(&m_items[i], std::move(oldItems[i]));
			oldItems[i].~T();
		}
		itRange = m_size;
		for (size_t i = pos; i < itRange; ++i) {
			std::construct_at(&m_items[i + offset], std::move(oldItems[i]));
			oldItems[i].~T();
		}
		this->deallocate(oldItems, oldCap);
	}
}


template<typename PlatSpec, typename T>
[[nodiscard]]
constexpr auto alignOf(Vector<T> const&) noexcept {
	typename PlatSpec::size_t const i = 0;
	return PlatSpec::alignOf(i);
}

}

OX_ALLOW_UNSAFE_BUFFERS_END
