Skip to content
Snippets Groups Projects
Commit d59ffd8e authored by Simon Praetorius's avatar Simon Praetorius
Browse files

Merge branch 'feature/integer-sequence-utilities' into 'master'

Add utilities to work with integer_sequence

See merge request !1351
parents ec43b34d 140e6356
No related branches found
No related tags found
1 merge request!1351Add utilities to work with integer_sequence
Pipeline #69123 passed
Pipeline: Dune Nightly Test

#69124

    ......@@ -60,6 +60,8 @@ In order to build the DUNE core modules you need at least the following software
    - Add dedicated includes `dune/common/metis.hh` for METIS and `dune/common/parallel/parmetis.hh`
    for ParMETIS to be used instead of the direct includes `metis.h` and `parmetis.h`.
    - Add utilities and algorithms to work with `std::integer_sequences`.
    ## Build System
    - Documentation files in `doc/buildsystem/${ModuleName}.rst` are now only copied.
    ......
    ......@@ -63,6 +63,7 @@ install(FILES
    hybridutilities.hh
    indent.hh
    indices.hh
    integersequence.hh
    interfaces.hh
    ios_state.hh
    iteratorfacades.hh
    ......
    // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
    // vi: set et ts=4 sw=2 sts=2:
    // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root
    // SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception
    #ifndef DUNE_COMMON_INTEGERSEQUENCE_HH
    #define DUNE_COMMON_INTEGERSEQUENCE_HH
    #include <algorithm>
    #include <array>
    #include <cassert>
    #include <functional>
    #include <type_traits>
    #include <utility>
    #include <dune/common/indices.hh>
    namespace Dune {
    //! Return the entry at position `pos` of the given sequence.
    template <std::size_t pos, class T, T... II,
    std::enable_if_t<(!(pos >= sizeof...(II))), int> = 0>
    constexpr auto get (std::integer_sequence<T,II...>, std::integral_constant<std::size_t,pos> = {})
    {
    constexpr T entry = std::array<T,sizeof...(II)>{II...}[pos];
    return std::integral_constant<T,entry>{};
    }
    //! Return the entry at position `pos` of the given sequence.
    template <class T, T... II>
    constexpr T get (std::integer_sequence<T,II...>, std::size_t pos)
    {
    assert(pos < sizeof...(II));
    return std::array<T,sizeof...(II)>{II...}[pos];
    }
    //! Return the first entry of the sequence.
    template <class T, T I0, T... II>
    constexpr std::integral_constant<T,I0>
    front (std::integer_sequence<T,I0,II...>) { return {}; }
    //! Return the last entry of the sequence.
    template <class T, T... II,
    std::enable_if_t<(sizeof...(II) > 0), int> = 0>
    constexpr auto back (std::integer_sequence<T,II...> seq)
    {
    return get<sizeof...(II)-1>(seq);
    }
    //! For a sequence [head,tail...) return the single head element.
    template <class T, T I0, T... II>
    constexpr std::integral_constant<T,I0>
    head (std::integer_sequence<T,I0,II...>) { return {}; }
    //! For a sequence [head,tail...) return the tail sequence.
    template <class T, T I0, T... II>
    constexpr std::integer_sequence<T,II...>
    tail (std::integer_sequence<T,I0,II...>) { return {}; }
    //! Append an index `I0` to the front of the sequence.
    template <auto I0, class T, T... II>
    constexpr std::integer_sequence<T,T(I0),II...>
    push_front (std::integer_sequence<T,II...>, std::integral_constant<T,I0> = {}) { return {}; }
    //! Append an index `IN` to the back of the sequence.
    template <auto IN, class T, T... II>
    constexpr std::integer_sequence<T,II...,T(IN)>
    push_back (std::integer_sequence<T,II...>, std::integral_constant<T,IN> = {}) { return {}; }
    //! Return the size of the sequence.
    template <class T, T... II>
    constexpr std::integral_constant<std::size_t,sizeof...(II)>
    size (std::integer_sequence<T,II...>) { return {}; }
    //! Checks whether the sequence is empty.
    template <class T, T... II>
    constexpr std::bool_constant<(sizeof...(II) == 0)>
    empty (std::integer_sequence<T,II...>) { return {}; }
    namespace Impl {
    // constexpr version of swap for older compilers
    template <class T>
    constexpr void swapImpl (T& a, T& b)
    {
    T c = a; a = b; b = c;
    }
    // constexpr quick sort implementation
    template <class T, std::size_t N, class Compare>
    constexpr void sortImpl (std::array<T, N>& array, Compare comp, std::size_t left = 0, std::size_t right = N)
    {
    // based on https://stackoverflow.com/a/40030044
    if (left < right) {
    std::size_t m = left;
    for (std::size_t i = left + 1; i < right; ++i)
    if (comp(array[i], array[left]))
    swapImpl(array[++m], array[i]);
    swapImpl(array[left], array[m]);
    sortImpl(array, comp, left, m);
    sortImpl(array, comp, m + 1, right);
    }
    }
    // return the sorted array
    template <class T, std::size_t N, class Compare>
    constexpr std::array<T, N> sortedImpl (std::array<T, N> array, Compare comp)
    {
    sortImpl(array, comp);
    return array;
    }
    } // end namespace Impl
    //! Sort a given sequence by the comparator `comp`.
    template <class T, T... II, class Compare>
    constexpr auto sorted (std::integer_sequence<T,II...> seq, Compare comp)
    {
    constexpr auto sorted = Impl::sortedImpl(std::array<T,sizeof...(II)>{II...}, comp);
    return unpackIntegerSequence([&](auto... i) {
    return std::integer_sequence<T,sorted[i]...>{};
    }, std::make_index_sequence<sizeof...(II)>{});
    }
    //! Sort a given sequence by less-than comparison.
    template <class T, T... II>
    constexpr auto sorted (std::integer_sequence<T,II...> seq)
    {
    return sorted(seq, std::less<T>{});
    }
    //! Checks whether or not a given sequence contains a value.
    template <class T, T... II, T value>
    constexpr std::bool_constant<((II == value) || ...)>
    contains (std::integer_sequence<T,II...>, std::integral_constant<T,value>) { return {}; }
    //! Return the elements from the sequence [II...) which are not found in the sequence [JJ...).
    template <class T, T... II, T... JJ>
    constexpr auto difference (std::integer_sequence<T,II...> iSeq, std::integer_sequence<T,JJ...> jSeq)
    {
    if constexpr(iSeq.size() == 0 || jSeq.size() == 0)
    return iSeq;
    else {
    constexpr auto I0 = head(iSeq);
    if constexpr(!contains(jSeq,I0))
    return push_front<I0.value>(difference(tail(iSeq),jSeq));
    else
    return difference(tail(iSeq),jSeq);
    }
    }
    //! Return the elements from the sequence [0,1,...N) which are not found in the sequence [JJ...).
    template <std::size_t N, class T, T... JJ,
    std::enable_if_t<(N >= sizeof...(JJ)), int> = 0>
    constexpr auto difference (std::integer_sequence<T,JJ...> jSeq)
    {
    return difference(std::make_integer_sequence<T,N>{}, jSeq);
    }
    //! Checks whether two sequences are identical.
    template <class S, S... II, class T, T... JJ,
    std::enable_if_t<(sizeof...(II) == sizeof...(JJ)), int> = 0,
    class ST = std::common_type_t<S,T>>
    constexpr std::is_same<std::integer_sequence<bool,true,(ST(II) == ST(JJ))...>,
    std::integer_sequence<bool,(ST(II) == ST(JJ))...,true>>
    equal (std::integer_sequence<S,II...>, std::integer_sequence<T,JJ...>) { return {}; }
    //! Sequences are unequal if not of the same length.
    template <class S, S... II, class T, T... JJ,
    std::enable_if_t<(sizeof...(II) != sizeof...(JJ)), int> = 0>
    constexpr std::bool_constant<false>
    equal (std::integer_sequence<S,II...>, std::integer_sequence<T,JJ...>) { return {}; }
    } // end namespace Dune
    #endif // DUNE_COMMON_INTEGERSEQUENCE_HH
    ......@@ -211,6 +211,9 @@ dune_add_test(SOURCES hybridutilitiestest.cc
    dune_add_test(SOURCES indicestest.cc
    LABELS quick)
    dune_add_test(SOURCES integersequencetest.cc
    LABELS quick)
    dune_add_test(SOURCES iscallabletest.cc
    LINK_LIBRARIES dunecommon
    LABELS quick)
    ......
    // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
    // vi: set et ts=4 sw=2 sts=2:
    // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root
    // SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception
    #ifdef HAVE_CONFIG_H
    #include "config.h"
    #endif
    #include <dune/common/indices.hh>
    #include <dune/common/integersequence.hh>
    int main()
    {
    using namespace Dune;
    using namespace Dune::Indices;
    auto seq0 = std::integer_sequence<int>{};
    static_assert(size(seq0) == 0);
    static_assert(empty(seq0) == true);
    auto seq1 = std::integer_sequence<int,0>{};
    static_assert(size(seq1) == 1);
    static_assert(empty(seq1) == false);
    static_assert(head(seq1) == std::integral_constant<int,0>{});
    static_assert(front(seq1) == head(seq1));
    static_assert(back(seq1) == head(seq1));
    static_assert(contains(seq1, std::integral_constant<int,0>{}) == true);
    static_assert(contains(seq1, std::integral_constant<int,1>{}) == false);
    auto seq2 = std::integer_sequence<int,0,1>{};
    auto seq2a = std::integer_sequence<int,1,0>{};
    static_assert(size(seq2) == 2);
    static_assert(empty(seq2) == false);
    static_assert(head(seq2) == std::integral_constant<int,0>{});
    static_assert(front(seq2) == head(seq2));
    static_assert(back(seq2) == head(tail(seq2)));
    static_assert(get<1>(seq2) == 1);
    static_assert(get(seq2,1) == 1);
    static_assert(contains(seq2, std::integral_constant<int,0>{}) == true);
    static_assert(contains(seq2, std::integral_constant<int,1>{}) == true);
    static_assert(contains(seq2, std::integral_constant<int,2>{}) == false);
    static_assert(equal(seq2, sorted(seq2a)));
    static_assert(equal(difference<4>(seq2),std::integer_sequence<int,2,3>{}));
    auto seq3 = std::integer_sequence<int,2,7,14>{};
    auto seq3a = std::integer_sequence<int,7,2,14>{};
    auto seq3b = std::integer_sequence<int,14,7,2>{};
    static_assert(size(seq3) == 3);
    static_assert(not equal(seq3, seq3a));
    static_assert(not equal(seq3, seq2));
    static_assert(equal(seq3, sorted(seq3a)));
    static_assert(equal(seq3b, sorted(seq3a,std::greater<>{})));
    static_assert(equal(push_front<2>(tail(seq3)), seq3));
    static_assert(equal(push_back<14>(std::integer_sequence<int,get<0>(seq3),get<1>(seq3)>{}), seq3));
    static_assert(empty(difference(seq3,seq3a)));
    static_assert(empty(difference(seq3a,seq3)));
    return 0;
    }
    0% Loading or .
    You are about to add 0 people to the discussion. Proceed with caution.
    Please register or to comment