/*
 * 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 http://mozilla.org/MPL/2.0/.
 *
 * Copyright 2019 Danny Robson <danny@nerdcruft.net>
 */

#pragma once

#include "../debug/assert.hpp"

#include <array>
#include <cstddef>
#include <iterator>

namespace cruft {
    /// A view of a compile-time sized array.
    ///
    /// \tparam S the number of elements
    /// \tparam T the data type of the elements
    template <std::size_t S, typename T>
    class varray {
    public:
        using iterator_category = std::random_access_iterator_tag;
        using value_type = T;
        using reference_type = T&;
        using pointer = T*;
        using difference_type = std::size_t;
        using size_type = std::size_t;

        //---------------------------------------------------------------------
        varray (varray const &rhs)
          : m_data (rhs.m_data)
        { ; }


        //-------------------------------------------------------------------------
        varray (std::array<T,S> &rhs)
          : m_data (std::data (rhs))
        { ; }


        varray (std::array<T,S> &&) = delete;


        //-------------------------------------------------------------------------
        varray (T (&_data)[S])
          : m_data (_data)
        { ; }


        template <typename ContainerT>
        varray (ContainerT &_container)
          : varray (_container.data ())
        { CHECK_GE (_container.size (), size ()); }


        //---------------------------------------------------------------------
        std::size_t size (void) const { return S; }

        T& operator[] (std::size_t i) { CHECK_INDEX (i,  S); return m_data[i]; }
        const T& operator[] (std::size_t i) const { CHECK_INDEX (i, S); return m_data[i]; }

        auto data (void) { return m_data; }
        auto data (void) const { return m_data; }

        auto begin (void) { return data (); }
        auto end   (void) { return data () + size (); }

        auto begin (void) const { return data (); }
        auto end   (void) const { return data () + size (); }

        auto cbegin (void) const { return data (); }
        auto cend   (void) const { return data () + size (); }

    private:
        T *m_data;
    };


    template <typename T, std::size_t S>
    varray (T(&)[S]) -> varray<S,T>;
}