// SPDX-License-Identifier: Apache-2.0
//
// Copyright 2008-2016 Conrad Sanderson (http://conradsanderson.id.au)
// Copyright 2008-2016 National ICT Australia (NICTA)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ------------------------------------------------------------------------

//! \addtogroup op_relational
//! @{

#undef operator_rel

#undef arma_applier_mat_pre
#undef arma_applier_mat_post

#undef arma_applier_cube_pre
#undef arma_applier_cube_post

#define arma_applier_mat_pre(operator_rel)                                            \
  {                                                                                   \
    typedef typename T1::elem_type eT;                                                \
    typedef typename Proxy<T1>::ea_type ea_type;                                      \
                                                                                      \
    const eT val = X.aux;                                                             \
                                                                                      \
    const Proxy<T1> P(X.m);                                                           \
                                                                                      \
    const uword n_rows = P.get_n_rows();                                              \
    const uword n_cols = P.get_n_cols();                                              \
                                                                                      \
    const bool bad_alias = (Proxy<T1>::has_subview && P.is_alias(out));               \
                                                                                      \
    if (bad_alias == false) {                                                         \
      out.set_size(n_rows, n_cols);                                                   \
                                                                                      \
      uword* out_mem = out.memptr();                                                  \
                                                                                      \
      if (Proxy<T1>::use_at == false) {                                               \
        ea_type PA = P.get_ea();                                                      \
        const uword n_elem = out.n_elem;                                              \
                                                                                      \
        for (uword i = 0; i < n_elem; ++i) {                                          \
          out_mem[i] = (val operator_rel PA[i]) ? uword(1) : uword(0);                \
        }                                                                             \
      } else {                                                                        \
        if (n_rows == 1) {                                                            \
          for (uword count = 0; count < n_cols; ++count) {                            \
            out_mem[count] = (val operator_rel P.at(0, count)) ? uword(1) : uword(0); \
          }                                                                           \
        } else {                                                                      \
          for (uword col = 0; col < n_cols; ++col)                                    \
            for (uword row = 0; row < n_rows; ++row) {                                \
              *out_mem = (val operator_rel P.at(row, col)) ? uword(1) : uword(0);     \
              out_mem++;                                                              \
            }                                                                         \
        }                                                                             \
      }                                                                               \
    } else {                                                                          \
      const Mat<eT> tmp(P.Q);                                                         \
                                                                                      \
      out = (val)operator_rel(tmp);                                                   \
    }                                                                                 \
  }

#define arma_applier_mat_post(operator_rel)                                           \
  {                                                                                   \
    typedef typename T1::elem_type eT;                                                \
    typedef typename Proxy<T1>::ea_type ea_type;                                      \
                                                                                      \
    const eT val = X.aux;                                                             \
                                                                                      \
    const Proxy<T1> P(X.m);                                                           \
                                                                                      \
    const uword n_rows = P.get_n_rows();                                              \
    const uword n_cols = P.get_n_cols();                                              \
                                                                                      \
    const bool bad_alias = (Proxy<T1>::has_subview && P.is_alias(out));               \
                                                                                      \
    if (bad_alias == false) {                                                         \
      out.set_size(n_rows, n_cols);                                                   \
                                                                                      \
      uword* out_mem = out.memptr();                                                  \
                                                                                      \
      if (Proxy<T1>::use_at == false) {                                               \
        ea_type PA = P.get_ea();                                                      \
        const uword n_elem = out.n_elem;                                              \
                                                                                      \
        for (uword i = 0; i < n_elem; ++i) {                                          \
          out_mem[i] = (PA[i] operator_rel val) ? uword(1) : uword(0);                \
        }                                                                             \
      } else {                                                                        \
        if (n_rows == 1) {                                                            \
          for (uword count = 0; count < n_cols; ++count) {                            \
            out_mem[count] = (P.at(0, count) operator_rel val) ? uword(1) : uword(0); \
          }                                                                           \
        } else {                                                                      \
          for (uword col = 0; col < n_cols; ++col)                                    \
            for (uword row = 0; row < n_rows; ++row) {                                \
              *out_mem = (P.at(row, col) operator_rel val) ? uword(1) : uword(0);     \
              out_mem++;                                                              \
            }                                                                         \
        }                                                                             \
      }                                                                               \
    } else {                                                                          \
      const Mat<eT> tmp(P.Q);                                                         \
                                                                                      \
      out = (tmp)operator_rel(val);                                                   \
    }                                                                                 \
  }

#define arma_applier_cube_pre(operator_rel)                                              \
  {                                                                                      \
    typedef typename T1::elem_type eT;                                                   \
    typedef typename ProxyCube<T1>::ea_type ea_type;                                     \
                                                                                         \
    const eT val = X.aux;                                                                \
                                                                                         \
    const ProxyCube<T1> P(X.m);                                                          \
                                                                                         \
    const uword n_rows = P.get_n_rows();                                                 \
    const uword n_cols = P.get_n_cols();                                                 \
    const uword n_slices = P.get_n_slices();                                             \
                                                                                         \
    const bool bad_alias = (ProxyCube<T1>::has_subview && P.is_alias(out));              \
                                                                                         \
    if (bad_alias == false) {                                                            \
      out.set_size(n_rows, n_cols, n_slices);                                            \
                                                                                         \
      uword* out_mem = out.memptr();                                                     \
                                                                                         \
      if (ProxyCube<T1>::use_at == false) {                                              \
        ea_type PA = P.get_ea();                                                         \
        const uword n_elem = out.n_elem;                                                 \
                                                                                         \
        for (uword i = 0; i < n_elem; ++i) {                                             \
          out_mem[i] = (val operator_rel PA[i]) ? uword(1) : uword(0);                   \
        }                                                                                \
      } else {                                                                           \
        for (uword slice = 0; slice < n_slices; ++slice)                                 \
          for (uword col = 0; col < n_cols; ++col)                                       \
            for (uword row = 0; row < n_rows; ++row) {                                   \
              *out_mem = (val operator_rel P.at(row, col, slice)) ? uword(1) : uword(0); \
              out_mem++;                                                                 \
            }                                                                            \
      }                                                                                  \
    } else {                                                                             \
      const unwrap_cube<typename ProxyCube<T1>::stored_type> tmp(P.Q);                   \
                                                                                         \
      out = (val)operator_rel(tmp.M);                                                    \
    }                                                                                    \
  }

#define arma_applier_cube_post(operator_rel)                                             \
  {                                                                                      \
    typedef typename T1::elem_type eT;                                                   \
    typedef typename ProxyCube<T1>::ea_type ea_type;                                     \
                                                                                         \
    const eT val = X.aux;                                                                \
                                                                                         \
    const ProxyCube<T1> P(X.m);                                                          \
                                                                                         \
    const uword n_rows = P.get_n_rows();                                                 \
    const uword n_cols = P.get_n_cols();                                                 \
    const uword n_slices = P.get_n_slices();                                             \
                                                                                         \
    const bool bad_alias = (ProxyCube<T1>::has_subview && P.is_alias(out));              \
                                                                                         \
    if (bad_alias == false) {                                                            \
      out.set_size(n_rows, n_cols, n_slices);                                            \
                                                                                         \
      uword* out_mem = out.memptr();                                                     \
                                                                                         \
      if (ProxyCube<T1>::use_at == false) {                                              \
        ea_type PA = P.get_ea();                                                         \
        const uword n_elem = out.n_elem;                                                 \
                                                                                         \
        for (uword i = 0; i < n_elem; ++i) {                                             \
          out_mem[i] = (PA[i] operator_rel val) ? uword(1) : uword(0);                   \
        }                                                                                \
      } else {                                                                           \
        for (uword slice = 0; slice < n_slices; ++slice)                                 \
          for (uword col = 0; col < n_cols; ++col)                                       \
            for (uword row = 0; row < n_rows; ++row) {                                   \
              *out_mem = (P.at(row, col, slice) operator_rel val) ? uword(1) : uword(0); \
              out_mem++;                                                                 \
            }                                                                            \
      }                                                                                  \
    } else {                                                                             \
      const unwrap_cube<typename ProxyCube<T1>::stored_type> tmp(P.Q);                   \
                                                                                         \
      out = (tmp.M)operator_rel(val);                                                    \
    }                                                                                    \
  }

template <typename T1>
inline void op_rel_lt_pre::apply(Mat<uword>& out,
                                 const mtOp<uword, T1, op_rel_lt_pre>& X) {
  arma_extra_debug_sigprint();

  arma_applier_mat_pre(<);
}

template <typename T1>
inline void op_rel_gt_pre::apply(Mat<uword>& out,
                                 const mtOp<uword, T1, op_rel_gt_pre>& X) {
  arma_extra_debug_sigprint();

  arma_applier_mat_pre(>);
}

template <typename T1>
inline void op_rel_lteq_pre::apply(Mat<uword>& out,
                                   const mtOp<uword, T1, op_rel_lteq_pre>& X) {
  arma_extra_debug_sigprint();

  arma_applier_mat_pre(<=);
}

template <typename T1>
inline void op_rel_gteq_pre::apply(Mat<uword>& out,
                                   const mtOp<uword, T1, op_rel_gteq_pre>& X) {
  arma_extra_debug_sigprint();

  arma_applier_mat_pre(>=);
}

template <typename T1>
inline void op_rel_lt_post::apply(Mat<uword>& out,
                                  const mtOp<uword, T1, op_rel_lt_post>& X) {
  arma_extra_debug_sigprint();

  arma_applier_mat_post(<);
}

template <typename T1>
inline void op_rel_gt_post::apply(Mat<uword>& out,
                                  const mtOp<uword, T1, op_rel_gt_post>& X) {
  arma_extra_debug_sigprint();

  arma_applier_mat_post(>);
}

template <typename T1>
inline void op_rel_lteq_post::apply(Mat<uword>& out,
                                    const mtOp<uword, T1, op_rel_lteq_post>& X) {
  arma_extra_debug_sigprint();

  arma_applier_mat_post(<=);
}

template <typename T1>
inline void op_rel_gteq_post::apply(Mat<uword>& out,
                                    const mtOp<uword, T1, op_rel_gteq_post>& X) {
  arma_extra_debug_sigprint();

  arma_applier_mat_post(>=);
}

template <typename T1>
inline void op_rel_eq::apply(Mat<uword>& out, const mtOp<uword, T1, op_rel_eq>& X) {
  arma_extra_debug_sigprint();

  arma_applier_mat_post(==);
}

template <typename T1>
inline void op_rel_noteq::apply(Mat<uword>& out, const mtOp<uword, T1, op_rel_noteq>& X) {
  arma_extra_debug_sigprint();

  arma_applier_mat_post(!=);
}

//
//
//

template <typename T1>
inline void op_rel_lt_pre::apply(Cube<uword>& out,
                                 const mtOpCube<uword, T1, op_rel_lt_pre>& X) {
  arma_extra_debug_sigprint();

  arma_applier_cube_pre(<);
}

template <typename T1>
inline void op_rel_gt_pre::apply(Cube<uword>& out,
                                 const mtOpCube<uword, T1, op_rel_gt_pre>& X) {
  arma_extra_debug_sigprint();

  arma_applier_cube_pre(>);
}

template <typename T1>
inline void op_rel_lteq_pre::apply(Cube<uword>& out,
                                   const mtOpCube<uword, T1, op_rel_lteq_pre>& X) {
  arma_extra_debug_sigprint();

  arma_applier_cube_pre(<=);
}

template <typename T1>
inline void op_rel_gteq_pre::apply(Cube<uword>& out,
                                   const mtOpCube<uword, T1, op_rel_gteq_pre>& X) {
  arma_extra_debug_sigprint();

  arma_applier_cube_pre(>=);
}

template <typename T1>
inline void op_rel_lt_post::apply(Cube<uword>& out,
                                  const mtOpCube<uword, T1, op_rel_lt_post>& X) {
  arma_extra_debug_sigprint();

  arma_applier_cube_post(<);
}

template <typename T1>
inline void op_rel_gt_post::apply(Cube<uword>& out,
                                  const mtOpCube<uword, T1, op_rel_gt_post>& X) {
  arma_extra_debug_sigprint();

  arma_applier_cube_post(>);
}

template <typename T1>
inline void op_rel_lteq_post::apply(Cube<uword>& out,
                                    const mtOpCube<uword, T1, op_rel_lteq_post>& X) {
  arma_extra_debug_sigprint();

  arma_applier_cube_post(<=);
}

template <typename T1>
inline void op_rel_gteq_post::apply(Cube<uword>& out,
                                    const mtOpCube<uword, T1, op_rel_gteq_post>& X) {
  arma_extra_debug_sigprint();

  arma_applier_cube_post(>=);
}

template <typename T1>
inline void op_rel_eq::apply(Cube<uword>& out, const mtOpCube<uword, T1, op_rel_eq>& X) {
  arma_extra_debug_sigprint();

  arma_applier_cube_post(==);
}

template <typename T1>
inline void op_rel_noteq::apply(Cube<uword>& out,
                                const mtOpCube<uword, T1, op_rel_noteq>& X) {
  arma_extra_debug_sigprint();

  arma_applier_cube_post(!=);
}

#undef arma_applier_mat_pre
#undef arma_applier_mat_post

#undef arma_applier_cube_pre
#undef arma_applier_cube_post

//! @}
