/*	Copyright (C) 2025 Catty Steve

	This file is part of the uClibc++ Library.
	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

	TODO: Currently untested
*/
#include <cstdint>
#include <iterator>
#include "basic_definitions"
#include <cassert>

namespace std {
    template<typename T, size_t N>
    struct array{
        // types
        typedef T value_type;
        typedef value_type* pointer;
        typedef const value_type* const_pointer;
        typedef value_type& reference;
        typedef const value_type& const_reference;
        typedef value_type* iterator;
        typedef const value_type* const_iterator;
        typedef size_t size_type;
        typedef ptrdiff_t difference_type;
        typedef std::reverse_iterator<iterator> reverse_iterator;
        typedef std::reverse_iterator<const_iterator> const_reverse_iterator;

        // support for zero-sized arrays currently not implemented
        T elements[N]={0,};

        void fill(const value_type & value) {
            std::fill(begin(), end(), value);
        }

        void swap(array& other) {
            std::swap_ranges(begin(), end(), other.begin());
        }

        UCLIBCXX_CONSTEXPR iterator begin() {
            return iterator(data());
        }

        UCLIBCXX_CONSTEXPR const_iterator begin() const {
            return const_iterator(data());
        }

        UCLIBCXX_CONSTEXPR iterator end() {
            return iterator(data() + N);
        }

        UCLIBCXX_CONSTEXPR const_iterator end() const {
            return const_iterator(data() + N);
        }

        UCLIBCXX_CONSTEXPR const_iterator cbegin() const {
            return const_iterator(data());
        }

        UCLIBCXX_CONSTEXPR const_iterator cend() const {
            return const_iterator(data() + N);
        }

        UCLIBCXX_CONSTEXPR reverse_iterator rbegin() {
            return reverse_iterator(end());
        }

        UCLIBCXX_CONSTEXPR const_reverse_iterator rbegin() const {
            return const_reverse_iterator(end());
        }

        UCLIBCXX_CONSTEXPR reverse_iterator rend() {
            return reverse_iterator(begin());
        }

        UCLIBCXX_CONSTEXPR const_reverse_iterator rend() const {
            return const_reverse_iterator(begin());
        }

        UCLIBCXX_CONSTEXPR const_reverse_iterator crbegin() const {
            return const_reverse_iterator(end());
        }

        UCLIBCXX_CONSTEXPR const_reverse_iterator crend() const {
            return const_reverse_iterator(begin());
        }

        UCLIBCXX_CONSTEXPR size_type size() const {
            return N;
        }

        UCLIBCXX_CONSTEXPR size_type max_size() const {
            return N;
        }

        UCLIBCXX_CONSTEXPR bool empty() const {
            return N == 0;
        }

        UCLIBCXX_CONSTEXPR reference operator[](size_type i) {
            return elements[i];
        }

        UCLIBCXX_CONSTEXPR const_reference operator[](size_type i) const {
            return elements[i];
        }

        UCLIBCXX_CONSTEXPR reference at(size_type i) {
            // if (i >= N) throw std::out_of_range("array::at");
            assert(i < N); // alternative without throwing exception
            return elements[i];
        }

        UCLIBCXX_CONSTEXPR const_reference at(size_type i) const {
            //if (i >= N) throw std::out_of_range("array::at");
            assert(i < N); // alternative without throwing exception
            return elements[i];
        }

        UCLIBCXX_CONSTEXPR const_reference front() const {
            return elements[(size_type)0];
        }

        UCLIBCXX_CONSTEXPR const_reference back() const {
            return elements[N - 1];
        }

        reference front() {
            return elements[(size_type)0];
        }

        reference back() {
            return elements[N - 1];
        }

        pointer data() {
            return static_cast<pointer>(elements);
        }

        const_pointer data() const {
            return static_cast<const_pointer>(elements);
        }
    };
    template <typename T, size_t N>
    bool operator == (const array<T, N> &lhs, const array<T, N> &rhs) {
        return std::equal(lhs.begin(), lhs.end(), rhs.begin());
    }

    template <typename T, size_t N>
    bool operator != (const array<T, N> &lhs, const array<T, N> &rhs) {
        return !(lhs == rhs);
    }

    template <typename T, size_t N>
    bool operator < (const array<T, N> &lhs, const array<T, N> &rhs) {
        return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
    }

    template <typename T, size_t N>
    bool operator > (const array<T, N> &lhs, const array<T, N> &rhs) {
        return rhs < lhs;
    }

    template <typename T, size_t N>
    bool operator <= (const array<T, N> &lhs, const array<T, N> &rhs) {
        return !(rhs < lhs);
    }

    template <typename T, size_t N>
    bool operator >= (const array<T, N> &lhs, const array<T, N> &rhs) {
        return !(lhs < rhs);
    }

    template <typename T, size_t N>
    void swap(array<T, N> &lhs, array<T, N> &rhs) {
        lhs.swap(rhs);
    }

}
