omni/Vector.h

File members: omni/Vector.h

// Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved.
//
// NVIDIA CORPORATION and its licensors retain all intellectual property
// and proprietary rights in and to this software, related documentation
// and any modifications thereto. Any use, reproduction, disclosure or
// distribution of this software and related documentation without an express
// license agreement from NVIDIA CORPORATION is strictly prohibited.
//
#pragma once

#include "detail/PointerIterator.h"
#include "detail/VectorDetail.h"
#include "../carb/Memory.h"

#include <memory>

namespace omni
{

template <class T>
class CARB_VIZ vector
{
public:
    using value_type = T;
    using allocator_type = typename ::carb::Allocator<T>;
    using size_type = std::size_t;
    using difference_type = std::ptrdiff_t;
    using reference = value_type&;
    using const_reference = const value_type&;
    using pointer = typename std::allocator_traits<allocator_type>::pointer;
    using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;
    using iterator = detail::PointerIterator<pointer, vector>;
    using const_iterator = detail::PointerIterator<const_pointer, vector>;
    using reverse_iterator = std::reverse_iterator<iterator>;
    using const_reverse_iterator = std::reverse_iterator<const_iterator>;

    CARB_CPP20_CONSTEXPR vector() noexcept;

    CARB_CPP20_CONSTEXPR explicit vector(const allocator_type&) noexcept : vector()
    {
    }

    CARB_CPP20_CONSTEXPR vector(size_type count, const T& value, const allocator_type& alloc = allocator_type());

    CARB_CPP20_CONSTEXPR vector(size_type count, const allocator_type& alloc = allocator_type());

    template <class InputIt CARB_NO_DOC(, std::enable_if_t<detail::IsLegacyInputIterator<InputIt>::value, bool> = false)>
    CARB_CPP20_CONSTEXPR vector(InputIt first, InputIt last, const allocator_type& = allocator_type())
    {
        _ranged_construct_or_reset(first, last, typename std::iterator_traits<InputIt>::iterator_category{});
    }

    CARB_CPP20_CONSTEXPR vector(const vector& other);

    CARB_CPP20_CONSTEXPR vector(const vector& other, const allocator_type&) : vector(other)
    {
    }

    CARB_CPP20_CONSTEXPR vector(vector&& other) noexcept;

    CARB_CPP20_CONSTEXPR vector(vector&& other, const allocator_type&) noexcept : vector(std::move(other))
    {
    }

    CARB_CPP20_CONSTEXPR vector(std::initializer_list<T> init, const allocator_type& alloc = allocator_type());

    CARB_CPP20_CONSTEXPR ~vector();

    CARB_CPP20_CONSTEXPR vector& operator=(const vector& other);

    CARB_CPP20_CONSTEXPR vector& operator=(vector&& other) noexcept;

    CARB_CPP20_CONSTEXPR vector& operator=(std::initializer_list<T> init);

    CARB_CPP20_CONSTEXPR void assign(size_type count, const T& value);

    template <class InputIt CARB_NO_DOC(, std::enable_if_t<detail::IsLegacyInputIterator<InputIt>::value, bool> = false)>
    CARB_CPP20_CONSTEXPR void assign(InputIt first, InputIt last)
    {
        _ranged_assign(first, last, typename std::iterator_traits<InputIt>::iterator_category{});
    }

    CARB_CPP20_CONSTEXPR void assign(std::initializer_list<T> init);

    CARB_CPP20_CONSTEXPR allocator_type get_allocator() const noexcept;

    CARB_CPP20_CONSTEXPR reference at(size_type pos);

    CARB_CPP20_CONSTEXPR const_reference at(size_type pos) const;

    CARB_CPP20_CONSTEXPR reference operator[](size_type pos);

    CARB_CPP20_CONSTEXPR const_reference operator[](size_type pos) const;

    CARB_CPP20_CONSTEXPR reference front();

    CARB_CPP20_CONSTEXPR const_reference front() const;

    CARB_CPP20_CONSTEXPR reference back();

    CARB_CPP20_CONSTEXPR const_reference back() const;

    CARB_CPP20_CONSTEXPR pointer data() noexcept;

    CARB_CPP20_CONSTEXPR const_pointer data() const noexcept;

    CARB_CPP20_CONSTEXPR iterator begin() noexcept
    {
        return iterator(m_first);
    }

    CARB_CPP20_CONSTEXPR const_iterator begin() const noexcept
    {
        return const_iterator(m_first);
    }

    CARB_CPP20_CONSTEXPR const_iterator cbegin() const noexcept
    {
        return begin();
    }

    CARB_CPP20_CONSTEXPR iterator end() noexcept
    {
        return iterator(m_last);
    }

    CARB_CPP20_CONSTEXPR const_iterator end() const noexcept
    {
        return const_iterator(m_last);
    }

    CARB_CPP20_CONSTEXPR const_iterator cend() const noexcept
    {
        return end();
    }

    CARB_CPP20_CONSTEXPR reverse_iterator rbegin() noexcept
    {
        return std::make_reverse_iterator(end());
    }

    CARB_CPP20_CONSTEXPR const_reverse_iterator rbegin() const noexcept
    {
        return std::make_reverse_iterator(end());
    }

    CARB_CPP20_CONSTEXPR const_reverse_iterator crbegin() const noexcept
    {
        return rbegin();
    }

    CARB_CPP20_CONSTEXPR reverse_iterator rend() noexcept
    {
        return std::make_reverse_iterator(begin());
    }

    CARB_CPP20_CONSTEXPR const_reverse_iterator rend() const noexcept
    {
        return std::make_reverse_iterator(begin());
    }

    CARB_CPP20_CONSTEXPR const_reverse_iterator crend() const noexcept
    {
        return rend();
    }

    CARB_NODISCARD CARB_CPP20_CONSTEXPR bool empty() const noexcept;

    CARB_NODISCARD CARB_CPP20_CONSTEXPR size_type size() const noexcept;

    CARB_NODISCARD CARB_CPP20_CONSTEXPR size_type max_size() const noexcept;

    CARB_CPP20_CONSTEXPR void reserve(size_type new_cap);

    CARB_NODISCARD CARB_CPP20_CONSTEXPR size_type capacity() const noexcept;

    CARB_CPP20_CONSTEXPR void shrink_to_fit();

    CARB_CPP20_CONSTEXPR void clear() noexcept;

    CARB_CPP20_CONSTEXPR iterator insert(const_iterator pos, const T& value);

    CARB_CPP20_CONSTEXPR iterator insert(const_iterator pos, T&& value);

    CARB_CPP20_CONSTEXPR iterator insert(const_iterator pos, size_type count, const T& value);

    template <class Iter CARB_NO_DOC(, std::enable_if_t<detail::IsLegacyInputIterator<Iter>::value, bool> = false)>
    CARB_CPP20_CONSTEXPR iterator insert(const_iterator pos, Iter first, Iter last)
    {
        return _ranged_insert(pos, first, last, typename std::iterator_traits<Iter>::iterator_category{});
    }

    CARB_CPP20_CONSTEXPR iterator insert(const_iterator pos, std::initializer_list<T> init);

    template <class... Args>
    CARB_CPP20_CONSTEXPR iterator emplace(const_iterator pos, Args&&... args);

    CARB_CPP20_CONSTEXPR iterator erase(const_iterator pos);

    CARB_CPP20_CONSTEXPR iterator erase(const_iterator first, const_iterator last);

    CARB_CPP20_CONSTEXPR void push_back(const T& value);

    CARB_CPP20_CONSTEXPR void push_back(T&& value);

    template <class... Args>
    CARB_CPP20_CONSTEXPR value_type& emplace_back(Args&&... args);

    CARB_CPP20_CONSTEXPR void pop_back();

    CARB_CPP20_CONSTEXPR void resize(size_type count);

    CARB_CPP20_CONSTEXPR void resize(size_type count, const value_type& value);

    CARB_CPP20_CONSTEXPR void swap(vector& other) noexcept;

private:
    bool _has_unused_capacity() const noexcept;
    size_type _unused_capacity() const noexcept;

    void _move_from(vector&& other) noexcept;

    size_type _calculate_growth(const size_type newSize) const;
    bool _purchase(const size_type cap);
    void _reset();
    void _reset(const pointer newVec, const size_type newSize, const size_type newCapacity);
    void _reallocate_exactly(const size_type newCapacity);

    static allocator_type& _get_allocator() noexcept;

    void _swap_all(vector&)
    {
        // Iterator debugging: Swap all iterators with another vector
    }
    void _orphan_all()
    {
        // Iterator debugging: all of our iterators are invalid
    }
    void _orphan_range(pointer, pointer)
    {
        // Iterator debugging: items in range (inclusive) are invalid
    }
    void _verify_iterator(const_iterator mine, bool allowEnd);

    template <class Iter>
    void _ranged_construct_or_reset(Iter first, Iter last, std::input_iterator_tag);
    template <class Iter>
    void _ranged_construct_or_reset(Iter first, Iter last, std::forward_iterator_tag);

    template <class Iter>
    void _ranged_assign(Iter first, Iter last, std::input_iterator_tag);
    template <class Iter>
    void _ranged_assign(Iter first, Iter last, std::forward_iterator_tag);

    template <class Iter>
    iterator _ranged_insert(const_iterator pos, Iter first, Iter last, std::input_iterator_tag);
    template <class Iter>
    iterator _ranged_insert(const_iterator pos, Iter first, Iter last, std::forward_iterator_tag);

    template <class... Args>
    value_type& _emplace_back_no_realloc(Args&&... args);

    template <class... Args>
    pointer _emplace_reallocate(const pointer where, Args&&... args);

    template <class Pred>
    void _internal_resize(const size_type count, Pred&& pred);

    static void _impl_uninit_noexcept_move_or_copy(pointer first, pointer last, pointer dest, std::true_type);
    static void _impl_uninit_noexcept_move_or_copy(pointer first, pointer last, pointer dest, std::false_type);
    static void _uninit_noexcept_move_or_copy(pointer first, pointer last, pointer dest);

    [[noreturn]] static void _length_error();
    [[noreturn]] static void _range_error();

    pointer m_first; // Beginning of array
    pointer m_last; // End of array
    pointer m_end; // End of allocated memory
};

template <class T>
CARB_NODISCARD inline bool operator==(const vector<T>& lhs, const vector<T>& rhs)
{
    return (lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin()));
}

template <class T>
CARB_NODISCARD inline bool operator!=(const vector<T>& lhs, const vector<T>& rhs)
{
    return !(lhs == rhs);
}

template <class T>
CARB_NODISCARD inline bool operator<(const vector<T>& lhs, const vector<T>& rhs)
{
    return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}

template <class T>
CARB_NODISCARD inline bool operator>(const vector<T>& lhs, const vector<T>& rhs)
{
    return (rhs < lhs);
}

template <class T>
CARB_NODISCARD inline bool operator<=(const vector<T>& lhs, const vector<T>& rhs)
{
    return !(rhs < lhs);
}

template <class T>
CARB_NODISCARD inline bool operator>=(const vector<T>& lhs, const vector<T>& rhs)
{
    return !(lhs < rhs);
}

template <>
class vector<bool>
{
private:
    vector() = default;
};

} // namespace omni

namespace std
{

template <class T>
void swap(omni::vector<T>& lhs, omni::vector<T>& rhs) noexcept
{
    lhs.swap(rhs);
}

} // namespace std

CARB_INCLUDE_PURIFY_TEST({
    using namespace omni;
    vector<vector<int>> v(5);
    vector<vector<int>> v2 = v;
    v.assign(v2.begin(), v2.end());
    v2.assign(5, {});
    v2.assign({});
    CARB_UNUSED(v.front(), v.back(), v.at(0), v[0], v.data(), v.cbegin(), v.cend(), v.rend(), v.rbegin(), v.crend());
    CARB_UNUSED(v.crbegin(), v.empty(), v.size(), v.max_size(), v.capacity());
    v.reserve(0);
    v.shrink_to_fit();
    v.clear();
    v.insert(v.begin(), decltype(v)::value_type{});
    v.insert(v.begin(), 5, decltype(v)::value_type{});
    v.insert(v.begin(), v2.begin(), v2.end());
    v.insert(v.begin(), std::initializer_list<decltype(v)::value_type>{});
    v.emplace(v.begin(), 5);
    v.erase(v.begin());
    v2.erase(v2.begin(), v2.end());
    v.push_back({});
    v.pop_back();
    v.resize(1);
    v.resize(2, {});
    v.swap(v2);
});

#if !defined __INTELLISENSE__
#    include "Vector.inl"
#endif