123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117 |
- // (c) Daniel Llorens - 2011-2013, 2015
- // 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 3 of the License, or (at your option) any
- // later version.
- /// @file opcheck.H
- /// @brief Check array argument agreement and select driving argument.
- #pragma once
- #include "ra/tuple-list.H"
- #include "ra/bootstrap.H"
- namespace ra {
- // Pick arg of largest rank as driver. Var rank counts as Inf, because it might
- // be larger. (This might be wrong; proper pick should be done at run time.) For
- // equal rank, prefer static size, because sizes must match. When I can pick
- // either, pick always the first.
- // TODO Should check dimensions down to smallest rank, as old opcheck() (??)
- // |-------------+----------+----------+--------------------|
- // | ranks B \ A | RANK_BAD | RANK_ANY | fixed |
- // |-------------+----------+----------+--------------------|
- // | RANK_BAD | A | A | A |
- // |-------------+----------+----------+--------------------|
- // | RANK_ANY | B | A | B |
- // |-------------+----------+----------+--------------------|
- // | fixed | B | A | A>B or check sizes |
- // |-------------+----------+----------+--------------------|
- // |-------------+---------+---------+-------|
- // | sizes B \ A | DIM_BAD | DIM_ANY | fixed |
- // |-------------+---------+---------+-------|
- // | DIM_BAD | A | A | A |
- // |-------------+---------+---------+-------|
- // | DIM_ANY | B | A | A |
- // |-------------+---------+---------+-------|
- // | fixed | B | B | A>=B |
- // |-------------+---------+---------+-------|
- template <class A, class B>
- struct pick_driver
- {
- constexpr static int ra = A::rank_s();
- constexpr static int rb = B::rank_s();
- constexpr static int sa = A::size_s();
- constexpr static int sb = B::size_s();
- constexpr static bool value_ =
- // check by rank
- rb==RANK_BAD
- ? 1
- : rb==RANK_ANY
- ? ra==RANK_ANY
- : ra==RANK_BAD
- ? 0
- : ra==RANK_ANY
- ? 1
- : ra>rb
- ? 1
- : ra<rb
- ? 0
- // check by size
- : sb==DIM_BAD
- ? 1
- : sa==DIM_BAD
- ? 0
- : sb==DIM_ANY
- ? 1
- : (sa!=DIM_ANY && sa>=sb);
- constexpr static int value = value_ ? 0 : 1; // 0 if ra wins, else 1
- };
- constexpr bool gt_rank(rank_t ra, rank_t rb)
- {
- return rb==RANK_BAD
- ? 1
- : rb==RANK_ANY
- ? ra==RANK_ANY
- : ra==RANK_BAD
- ? 0
- : ra==RANK_ANY
- ? 1
- : ra>=rb;
- }
- template <class A, class B>
- struct max_i
- {
- constexpr static int value = gt_rank(A::value, B::value) ? 0 : 1; // 0 if ra wins, else 1
- };
- template <class ... P> using largest_rank = mp::IndexOf<pick_driver, std::tuple<P ...>>;
- template <class ... P> using largest_i = mp::IndexOf<max_i, std::tuple<P ...>>;
- template <class T> using largest_i_tuple = mp::IndexOf<max_i, T>;
- // TODO Allow infinite rank; need a special value of crank for that.
- inline constexpr rank_t dependent_cell_rank(rank_t rank, rank_t crank)
- {
- return crank>=0 ? crank // not dependent
- : rank==RANK_ANY ? RANK_ANY // defer
- : rank+crank;
- }
- inline constexpr rank_t dependent_frame_rank(rank_t rank, rank_t crank)
- {
- return rank==RANK_ANY ? RANK_ANY // defer
- : crank>=0 ? rank-crank // not dependent
- : -crank;
- }
- } // namespace ra
|