/*
 * GridTools
 *
 * Copyright (c) 2014-2019, ETH Zurich
 * All rights reserved.
 *
 * Please, refer to the LICENSE file in the root directory.
 * SPDX-License-Identifier: BSD-3-Clause
 */
#include <gridtools/common/layout_map.hpp>
#include <gridtools/common/layout_map_metafunctions.hpp>

using namespace gridtools;

namespace simple_layout {
    typedef layout_map<0, 1, 2> layout1;

    // test length
    static_assert(layout1::masked_length == 3, "");
    static_assert(layout1::unmasked_length == 3, "");

    // test find method
    static_assert(layout1::find(0) == 0, "");
    static_assert(layout1::find(1) == 1, "");
    static_assert(layout1::find(2) == 2, "");

    // test at method
    static_assert(layout1::at(0) == 0, "");
    static_assert(layout1::at(1) == 1, "");
    static_assert(layout1::at(2) == 2, "");
} // namespace simple_layout

namespace extended_layout {
    typedef layout_map<3, 2, 1, 0> layout2;

    // test length
    static_assert(layout2::masked_length == 4, "");
    static_assert(layout2::unmasked_length == 4, "");

    // test find method
    static_assert(layout2::find(0) == 3, "");
    static_assert(layout2::find(1) == 2, "");
    static_assert(layout2::find(2) == 1, "");
    static_assert(layout2::find(3) == 0, "");

    // test at method
    static_assert(layout2::at(0) == 3, "");
    static_assert(layout2::at(1) == 2, "");
    static_assert(layout2::at(2) == 1, "");
    static_assert(layout2::at(3) == 0, "");
} // namespace extended_layout

namespace masked_layout {
    typedef layout_map<2, -1, 1, 0> layout3;

    // test length
    static_assert(layout3::masked_length == 4, "");
    static_assert(layout3::unmasked_length == 3, "");

    // test find method
    static_assert(layout3::find(0) == 3, "");
    static_assert(layout3::find(1) == 2, "");
    static_assert(layout3::find(2) == 0, "");

    // test at method
    static_assert(layout3::at(0) == 2, "");
    static_assert(layout3::at(1) == -1, "");
    static_assert(layout3::at(2) == 1, "");
    static_assert(layout3::at(3) == 0, "");
} // namespace masked_layout

namespace default_layout {
    template <int N, int... Is>
    constexpr bool testee = std::is_same<layout_map<Is...>, typename default_layout_map<N>::type>::value;

    static_assert(testee<1, 0>, "");
    static_assert(testee<2, 0, 1>, "");
    static_assert(testee<3, 0, 1, 2>, "");
    static_assert(testee<4, 0, 1, 2, 3>, "");
} // namespace default_layout

namespace extender {
    typedef layout_map<0, 1, 2> layout;

    template <class Layout, int... Is>
    constexpr bool testee = std::is_same<layout_map<Is...>, Layout>::value;

    typedef typename extend_layout_map<layout, 1>::type ext_layout_1;
    static_assert(testee<ext_layout_1, 1, 2, 3, 0>, "");

    typedef typename extend_layout_map<layout, 2>::type ext_layout_2;
    static_assert(testee<ext_layout_2, 2, 3, 4, 0, 1>, "");

    typedef typename extend_layout_map<layout, 3>::type ext_layout_3;
    static_assert(testee<ext_layout_3, 3, 4, 5, 0, 1, 2>, "");

    typedef typename extend_layout_map<layout, 1, insert_location::pre>::type ext_layout_post_1;
    static_assert(testee<ext_layout_post_1, 0, 1, 2, 3>, "");

    // try the same again with a special layout
    typedef layout_map<2, 1, -1, 0> special_layout;

    typedef typename extend_layout_map<special_layout, 1>::type ext_special_layout_1;
    static_assert(testee<ext_special_layout_1, 3, 2, -1, 1, 0>, "");

    typedef typename extend_layout_map<special_layout, 2>::type ext_special_layout_2;
    static_assert(testee<ext_special_layout_2, 4, 3, -1, 2, 0, 1>, "");

    typedef typename extend_layout_map<special_layout, 3>::type ext_special_layout_3;
    static_assert(testee<ext_special_layout_3, 5, 4, -1, 3, 0, 1, 2>, "");

    typedef typename extend_layout_map<special_layout, 1, insert_location::pre>::type ext_special_layout_post_1;
    static_assert(testee<ext_special_layout_post_1, 0, 3, 2, -1, 1>, "");

    typedef typename extend_layout_map<special_layout, 2, insert_location::pre>::type ext_special_layout_post_2;
    static_assert(testee<ext_special_layout_post_2, 0, 1, 4, 3, -1, 2>, "");
} // namespace extender
