/*
 * Copyright (C) 2020-2021 Aloysius Indrayanto
 *
 * This file is part of the eCxx library, see LICENSE file for the license details.
 */


#ifndef ECXX_CTL_ARRAY_H
#define ECXX_CTL_ARRAY_H


#include <eCxx/CTL/AlignedStorage.h>
#include <eCxx/CTL/InitializerList.h>
#include <eCxx/CTL/Utility.h>


namespace eCxx {


//
// A simple array
//
// WARNING : All functions that accept 'PGMVoidPointer' and 'PGMVoidPointerFar' as their parameters
//           expect the pointers to come from program memory exclusively!
//
// NOTE    : Whenever possible, use the near program pointer because the far one has more overhead
//           and restrictions.
//
template <typename ValueT, size_t MaxCapacity>
class Array {
    public:
        typedef       ValueT  ValueType;
        typedef       size_t  SizeType;

        typedef       ValueT& Reference;
        typedef const ValueT& ConstReference;

        typedef       ValueT* Pointer;
        typedef const ValueT* ConstPointer;

        typedef       ValueT* Iterator;
        typedef const ValueT* ConstIterator;

        static constexpr SizeType ValueSize = sizeof(ValueType);
        static constexpr SizeType Capacity  = MaxCapacity;

    public:
        inline Array() noexcept;
        inline Array(const Array& array) noexcept;
        inline Array(Array&& array) noexcept;
        inline Array(InitializerList<ValueType> values) noexcept;

        template <size_t OtherMaxCapacity> inline Array(const Array<ValueType, OtherMaxCapacity>& array) noexcept;
        template <size_t OtherMaxCapacity> inline Array(Array<ValueType, OtherMaxCapacity>&& array) noexcept;

        template <typename PGMMemCpyFunctorT = PGMMemCpy> inline Array(PGMVoidPointer    ptr, SizeType num) noexcept;
        template <typename PGMMemCpyFunctorT = PGMMemCpy> inline Array(PGMVoidPointerFar ptr, SizeType num) noexcept;

        inline ~Array() noexcept;

        inline Array& operator=(const Array& array) noexcept;
        inline Array& operator=(Array&& array) noexcept;

        template <size_t OtherMaxCapacity> inline Array& operator=(const Array<ValueType, OtherMaxCapacity>& array) noexcept;
        template <size_t OtherMaxCapacity> inline Array& operator=(Array<ValueType, OtherMaxCapacity>&& array) noexcept;

        inline SizeType capacity() const noexcept;
        inline SizeType size() const noexcept;

        inline bool empty() const noexcept;
        inline void clear() noexcept;
        inline void resize(SizeType size) noexcept;

        inline void pushBack(const ValueType& value) noexcept;
        inline void pushBack(ValueType&& value) noexcept;
        inline void popBack() noexcept;

        inline bool operator==(const Array& array) const noexcept;
        inline bool operator!=(const Array& array) const noexcept;

        template <typename PGMMemCpyFunctorT = PGMMemCpy> inline bool equalsTo(PGMVoidPointer    ptr, SizeType num) const noexcept;
        template <typename PGMMemCpyFunctorT = PGMMemCpy> inline bool equalsTo(PGMVoidPointerFar ptr, SizeType num) const noexcept;

        inline ConstPointer data() const noexcept;

        inline Reference front() noexcept;
        inline ConstReference front() const noexcept;

        inline Reference back() noexcept;
        inline ConstReference back() const noexcept;

        inline Reference operator[] (SizeType index) noexcept;
        inline ConstReference operator[] (SizeType index) const noexcept;

        inline Iterator begin() noexcept;
        inline Iterator end() noexcept;

        inline ConstIterator cbegin() const noexcept;
        inline ConstIterator cend() const noexcept;

    private:
        template <typename ValueU, size_t OtherMaxCapacity>
        friend struct ArrayHelper;

    private:
        SizeType                            _size;
        AlignedStorage<ValueType, Capacity> _array;
};


//
// Include the implementation file
//
#define INCLUDE_ECXX_CTL_ARRAY_TPP
#include "Array.tpp"


} // namespace eCxx


#endif
