/*******************************************************************************
*
* TRIQS: a Toolbox for Research in Interacting Quantum Systems
*
* Copyright (C) 2011 by O. Parcollet
*
* TRIQS is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* TRIQS is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* TRIQS. If not, see .
*
******************************************************************************/
#ifndef TRIQS_ARRAYS_ASSIGN2_H_
#define TRIQS_ARRAYS_ASSIGN2_H_
#include "iterator_adapter.hpp"
#include "../indexmaps/cuboid/foreach.hpp"
#include "../storages/memcopy.hpp"
// two ways of doing things... optimal one depends on compiler ? To be checked...
#define TRIQS_ARRAYS_ASSIGN_ISP_WITH_FOREACH
namespace triqs { namespace arrays {
namespace Tag {struct indexmap_storage_pair{}; }// defined here since needed below...
namespace assignment { template struct impl; }
// puts the contents of RHS into LHS. LHS must be an indexmap_storage_pair
// it is specialized in various cases for optimisation.
template
void triqs_arrays_assign_delegation (LHS & lhs, const RHS & rhs ) { assignment::impl(lhs,rhs).invoke();}
template
void triqs_arrays_compound_assign_delegation (LHS & lhs, const RHS & rhs, mpl::char_ ) { assignment::impl(lhs,rhs).invoke();}
#define TRIQS_DEFINE_COMPOUND_OPERATORS(MYTYPE)\
template MYTYPE & operator +=(RHS const & rhs) { triqs_arrays_compound_assign_delegation (*this,rhs, mpl::char_<'A'>()); return *this;}\
template MYTYPE & operator -=(RHS const & rhs) { triqs_arrays_compound_assign_delegation (*this,rhs, mpl::char_<'S'>()); return *this;}\
template MYTYPE & operator *=(RHS const & rhs) { triqs_arrays_compound_assign_delegation (*this,rhs, mpl::char_<'M'>()); return *this;}\
template MYTYPE & operator /=(RHS const & rhs) { triqs_arrays_compound_assign_delegation (*this,rhs, mpl::char_<'D'>()); return *this;}
#define TRIQS_DELETE_COMPOUND_OPERATORS(MYTYPE)\
template MYTYPE & operator +=(RHS const & rhs) = delete;\
template MYTYPE & operator -=(RHS const & rhs) = delete;\
template MYTYPE & operator *=(RHS const & rhs) = delete;\
template MYTYPE & operator /=(RHS const & rhs) = delete;
// -------- IMPLEMENTATION ----------------------------
namespace assignment {
template struct _ops_;
template struct _ops_ { static void invoke (A & a, B const & b) { a =b;} };
template struct _ops_ { static void invoke (A & a, B const & b) { a+=b;} };
template struct _ops_ { static void invoke (A & a, B const & b) { a-=b;} };
template struct _ops_ { static void invoke (A & a, B const & b) { a*=b;} };
template struct _ops_ { static void invoke (A & a, B const & b) { a/=b;} };
// RHS is considered to be an indexmap_storage_pair if it is one, ... except if it is the scalar type of hte LHS
// think about an Array< Array > e.g.
template struct is_isp :
std::integral_constant::value && (!is_scalar_for::value) > {};
#define TRIQS_REJECT_ASSIGN_TO_CONST \
static_assert( (!std::is_const::value ), "Assignment : The value type of the LHS is const and can not be assigned to !");
#define TRIQS_REJECT_MATRIX_COMPOUND_MUL_DIV_NON_SCALAR\
static_assert( (!((OP=='M' || OP=='D') && MutableMatrix::value && (!is_scalar_for::value))),\
"*= and /= operator for non scalar RHS are deleted for a type modeling MutableMatrix (e.g. matrix, matrix_view) matrix, because this is ambiguous");
// ----------------- standard assignment for indexmap_storage_pair --------------------------------------------------
template
struct impl) > {
TRIQS_REJECT_ASSIGN_TO_CONST;
TRIQS_REJECT_MATRIX_COMPOUND_MUL_DIV_NON_SCALAR;
typedef typename LHS::value_type value_type;
typedef typename LHS::indexmap_type indexmap_type;
typedef typename indexmap_type::domain_type::index_value_type index_value_type;
LHS & lhs; const RHS & rhs;
typedef typename std::remove_cv::type v_t;
impl(LHS & lhs_, const RHS & rhs_): lhs(lhs_), rhs(rhs_) {}
template void operator()(Args const & ... args) const {
// void operator()(value_type & p, index_value_type const & key) {
_ops_::type, typename RHS::value_type, OP>::invoke(lhs(args...), rhs(args...)) ;}
void invoke () {
#ifdef TRIQS_ARRAYS_DEBUG
if (!indexmaps::compatible_for_assignment(lhs.indexmap(), rhs.indexmap())) TRIQS_RUNTIME_ERROR<< "Size mismatch in operation "<