3
0
mirror of https://github.com/triqs/dft_tools synced 2024-12-25 13:53:40 +01:00

arrays : add ConstView to fix const correctness

- A()(0) = 1
will not work any more if A is const, as it should be.

- Introduced the notion of const_view, simply done by a flag
(flag 0, for easy debug)
- changed the slice of ISP to use it (only on C++11 compliant compiler)
- Move BoundCheck Flags to 5.
This commit is contained in:
Olivier Parcollet 2013-06-30 19:27:42 +02:00
parent fc2a620eae
commit 552c440238
6 changed files with 150 additions and 27 deletions

View File

@ -0,0 +1,41 @@
/*******************************************************************************
*
* 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 <http://www.gnu.org/licenses/>.
*
******************************************************************************/
#include "./common.hpp"
#include "./src/array.hpp"
#include <iostream>
using namespace triqs::arrays;
int main(int argc, char **argv) {
const array<long,1> A = {1,2,3,4};
std::cerr << A.opt_flags<<std::endl;
std::cerr << A().opt_flags<<std::endl;
// None of this should compile
//A(0) = 2;
//A()(0) = 2;
//A(range(0,2))(0) = 10;
return 0;
}

View File

@ -0,0 +1,78 @@
/*******************************************************************************
*
* 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 <http://www.gnu.org/licenses/>.
*
******************************************************************************/
#include "./common.hpp"
#include "./src/array.hpp"
#include <iostream>
using namespace triqs::arrays;
auto bad (array<long,1> const & a) DECL_AND_RETURN (a(range(0,3)));
auto bad2 (array<long,1> const & a) DECL_AND_RETURN (a(0));
array_view<long,1> good(array<long,1> const & a) {return a(range(0,3));}
int main(int argc, char **argv) {
try {
array<long,1> A = {1,2,3,4};
std::cerr<<"A is "<<A<<std::endl;
{
auto r = A(range(0,3));
TEST_ASSERT(r.storage().is_weak);
}
{
auto r = array<long,1> {1,2,3,4} (range(0,3));
TEST_ASSERT(!r.storage().is_weak);
std::cerr << r << r.storage().is_weak << std::endl ;
}
{
auto r = array<long,1> {1,2,3,4} (range(0,3))();
std::cerr << r << r.storage().is_weak << std::endl ;
TEST_ASSERT(!r.storage().is_weak);
}
{
auto r = good ( { 1,2,3,4} );
std::cerr << " good "<< r << r.storage().is_weak << std::endl ;
}
{
auto & r = bad2 ( { 1,2,3,4} );
std::cerr << " bad2 " << r << std::endl ;
}
{
auto r = bad ( { 1,2,3,4} );
std::cerr << " bad " << r << r.storage().is_weak << std::endl ;
}
}
catch (std::exception & e) { std::cout << e.what()<<std::endl;}
return 0;
}

View File

@ -55,13 +55,14 @@ namespace boost { namespace serialization { class access;}}
#define TRIQS_ARRAYS_ENFORCE_BOUNDCHECK #define TRIQS_ARRAYS_ENFORCE_BOUNDCHECK
#define TRIQS_ARRAYS_CHECK_IM_STORAGE_COMPAT #define TRIQS_ARRAYS_CHECK_IM_STORAGE_COMPAT
#define TRIQS_ARRAYS_CHECK_WEAK_REFS
#else #else
#define TRIQS_ARRAYS_DEBUG_CHECK(Cond,Error) #define TRIQS_ARRAYS_DEBUG_CHECK(Cond,Error)
#endif #endif
// In particular, gcc 4.6, 4.7 do not have "rvalue for *this", which forbid the implementation // In particular, gcc 4.6, 4.7 do not have "rvalue for *this", which forbid the implementation
// of weak references. In that we, we will revert to strong view instead. // of weak references. In that case, we will revert to strong view instead.
#ifdef TRIQS_COMPILER_IS_OBSOLETE #ifdef TRIQS_COMPILER_IS_OBSOLETE
#define TRIQS_ARRAYS_SLICE_DEFAUT_IS_SHARED #define TRIQS_ARRAYS_SLICE_DEFAUT_IS_SHARED
#endif #endif

View File

@ -27,18 +27,18 @@ namespace triqs { namespace arrays {
// Flags is a 64 bit unsigned int. // Flags is a 64 bit unsigned int.
// 0 is the default option. // 0 is the default option.
// Meaning of the bits : // Meaning of the bits :
// 0 -> Boundcheck // 0 -> Const
// 1,2 -> Predefined order : // 1,2 -> Predefined order :
// 0 : None, 1 : C, 2 : Fortran // 0 : None, 1 : C, 2 : Fortran
// 3,4 -> Init // 3 -> Init the array
// 0 : Noinit, 1 : NanInit, 2 : DefaultInit // 5 -> Boundcheck
constexpr ull_t BoundCheck = 1ull << 0; constexpr ull_t ConstView = 1ull << 0;
constexpr ull_t TraversalOrderC = 1ull << 1; constexpr ull_t TraversalOrderC = 1ull << 1;
constexpr ull_t TraversalOrderFortran = 1ull << 2; constexpr ull_t TraversalOrderFortran = 1ull << 2;
//constexpr ull_t NanInit = 1ull << 3; constexpr ull_t DefaultInit = 1ull << 3;
constexpr ull_t DefaultInit = 1ull << 4; constexpr ull_t BoundCheck = 1ull << 5;
#define BOUND_CHECK triqs::arrays::BoundCheck #define BOUND_CHECK triqs::arrays::BoundCheck
#define TRAVERSAL_ORDER_C triqs::arrays::TraversalOrderC #define TRAVERSAL_ORDER_C triqs::arrays::TraversalOrderC
@ -55,10 +55,12 @@ namespace triqs { namespace arrays {
constexpr ull_t get(ull_t f, ull_t a) { return ((f & (1ull<<a)) >> a);} constexpr ull_t get(ull_t f, ull_t a) { return ((f & (1ull<<a)) >> a);}
constexpr ull_t get2(ull_t f, ull_t a) { return ((f & ((1ull<<a) + (1ull<< (a+1ull)))) >> a);} constexpr ull_t get2(ull_t f, ull_t a) { return ((f & ((1ull<<a) + (1ull<< (a+1ull)))) >> a);}
constexpr bool is_const (ull_t f) { return get (f,0) !=0;}
#ifdef TRIQS_ARRAYS_ENFORCE_BOUNDCHECK #ifdef TRIQS_ARRAYS_ENFORCE_BOUNDCHECK
constexpr bool bound_check (ull_t f) { return true;} constexpr bool bound_check (ull_t f) { return true;}
#else #else
constexpr bool bound_check (ull_t f) { return get (f, 0)!=0;} constexpr bool bound_check (ull_t f) { return get (f, 5)!=0;}
#endif #endif
constexpr bool traversal_order_c (ull_t f) { return get (f,1ull)!=0ull;} constexpr bool traversal_order_c (ull_t f) { return get (f,1ull)!=0ull;}
@ -66,13 +68,11 @@ namespace triqs { namespace arrays {
template< ull_t F> struct bound_check_trait { static constexpr bool value = bound_check(F); }; template< ull_t F> struct bound_check_trait { static constexpr bool value = bound_check(F); };
constexpr ull_t init_mode (ull_t f) { return get2 (f,3);} constexpr ull_t init_mode (ull_t f) { return get (f,3);}
constexpr bool check_init_mode (ull_t f) { return get2 (f,3)!=3ull;}
template<ull_t F> struct init_tag1; template<ull_t F> struct init_tag1;
template<> struct init_tag1<0> { typedef Tag::no_init type;}; template<> struct init_tag1<0> { typedef Tag::no_init type;};
//template<> struct init_tag1<1> { typedef Tag::nan_inf_init type;}; template<> struct init_tag1<1> { typedef Tag::default_init type;};
template<> struct init_tag1<2> { typedef Tag::default_init type;};
// for the init_tag, we pass the *whole* option flag. // for the init_tag, we pass the *whole* option flag.
template<ull_t F> struct init_tag : init_tag1 < init_mode(F)> {}; template<ull_t F> struct init_tag : init_tag1 < init_mode(F)> {};
@ -81,21 +81,21 @@ namespace triqs { namespace arrays {
static constexpr bool bc = bound_check(F); static constexpr bool bc = bound_check(F);
static constexpr bool is_c = traversal_order_c(F); static constexpr bool is_c = traversal_order_c(F);
static constexpr bool is_f = traversal_order_fortran(F); static constexpr bool is_f = traversal_order_fortran(F);
static constexpr bool inm = check_init_mode(F);
static_assert ( (!( is_c && is_f)), "You asked C and Fortran traversal order at the same time..."); static_assert ( (!( is_c && is_f)), "You asked C and Fortran traversal order at the same time...");
static_assert ( (!( (is_c || is_f) && To )), "You asked C or Fortran traversal order and gave a traversal order ..."); static_assert ( (!( (is_c || is_f) && To )), "You asked C or Fortran traversal order and gave a traversal order ...");
static_assert ( (inm), "You asked nan and default init at the same time...");
}; };
#else #else
#define TRIQS_FLAGS_GET(f,a) ((f & (1ull<<a)) >> a) #define TRIQS_FLAGS_GET(f,a) ((f & (1ull<<a)) >> a)
#define TRIQS_FLAGS_GET2(f,a) ((f & ((1ull<<a) + (1ull<< (a+1ull)))) >> a) #define TRIQS_FLAGS_GET2(f,a) ((f & ((1ull<<a) + (1ull<< (a+1ull)))) >> a)
constexpr bool is_const (ull_t f) { return false;} // non const view on icc
#ifdef TRIQS_ARRAYS_ENFORCE_BOUNDCHECK #ifdef TRIQS_ARRAYS_ENFORCE_BOUNDCHECK
template< ull_t F> struct bound_check_trait { static constexpr bool value = true;}; template< ull_t F> struct bound_check_trait { static constexpr bool value = true;};
#else #else
template< ull_t F> struct bound_check_trait { static constexpr bool value = TRIQS_FLAGS_GET (F, 0)!=0; }; template< ull_t F> struct bound_check_trait { static constexpr bool value = TRIQS_FLAGS_GET (F, 5)!=0; };
#endif #endif
template< ull_t F> struct traversal_order_c { static constexpr bool value = TRIQS_FLAGS_GET(F,1) !=0; }; template< ull_t F> struct traversal_order_c { static constexpr bool value = TRIQS_FLAGS_GET(F,1) !=0; };
@ -105,8 +105,7 @@ namespace triqs { namespace arrays {
template<ull_t F> struct init_tag1; template<ull_t F> struct init_tag1;
template<> struct init_tag1<0> { typedef Tag::no_init type;}; template<> struct init_tag1<0> { typedef Tag::no_init type;};
//template<> struct init_tag1<1> { typedef Tag::nan_inf_init type;}; template<> struct init_tag1<1> { typedef Tag::default_init type;};
template<> struct init_tag1<2> { typedef Tag::default_init type;};
template<ull_t F> struct init_tag : init_tag1 < init_mode_tr<F>::value > {}; template<ull_t F> struct init_tag : init_tag1 < init_mode_tr<F>::value > {};
template<ull_t F, ull_t To> struct assert_make_sense { };// no check on icc template<ull_t F, ull_t To> struct assert_make_sense { };// no check on icc

View File

@ -52,6 +52,7 @@ namespace triqs { namespace arrays {
typedef StorageType storage_type; typedef StorageType storage_type;
typedef IndexMapType indexmap_type; typedef IndexMapType indexmap_type;
static constexpr unsigned int rank = IndexMapType::domain_type::rank; static constexpr unsigned int rank = IndexMapType::domain_type::rank;
static constexpr ull_t opt_flags = OptionFlags;
protected: protected:
indexmap_type indexmap_; indexmap_type indexmap_;
@ -188,7 +189,7 @@ namespace triqs { namespace arrays {
// Evaluation and slices // Evaluation and slices
template<typename... Args> template<typename... Args>
typename std::enable_if< typename std::enable_if<
(!clef::is_any_lazy<Args...>::value) && (indexmaps::slicer<indexmap_type,Args...>::r_type::domain_type::rank==0) (!clef::is_any_lazy<Args...>::value) && (indexmaps::slicer<indexmap_type,Args...>::r_type::domain_type::rank==0) && !flags::is_const(OptionFlags)
, value_type &>::type , value_type &>::type
operator()(Args const & ... args) { return storage_[indexmap_(args...)]; } operator()(Args const & ... args) { return storage_[indexmap_(args...)]; }
@ -203,7 +204,8 @@ namespace triqs { namespace arrays {
//typedef typename std::conditional<is_const, typename std::add_const<value_type>::type, value_type>::type V2; //typedef typename std::conditional<is_const, typename std::add_const<value_type>::type, value_type>::type V2;
typedef value_type V2; typedef value_type V2;
static_assert(IM2::domain_type::rank !=0, "Internal error"); static_assert(IM2::domain_type::rank !=0, "Internal error");
typedef typename ISPViewType<V2,IM2::domain_type::rank, OptionFlags, IM2::traversal_order_in_template, ViewTag, ForceBorrowed || StorageType::is_weak >::type type; static constexpr ull_t optmodif = (is_const ? ConstView : 0ull);
typedef typename ISPViewType<V2,IM2::domain_type::rank, OptionFlags|optmodif, IM2::traversal_order_in_template, ViewTag, ForceBorrowed || StorageType::is_weak >::type type;
}; };
// change here only for debug // change here only for debug
@ -211,7 +213,7 @@ namespace triqs { namespace arrays {
#ifndef TRIQS_ARRAYS_SLICE_DEFAUT_IS_SHARED #ifndef TRIQS_ARRAYS_SLICE_DEFAUT_IS_SHARED
template<typename... Args> // non const version template<typename... Args> // non const version
typename boost::lazy_enable_if_c< typename boost::lazy_enable_if_c<
(!clef::is_any_lazy<Args...>::value) && (indexmaps::slicer<indexmap_type,Args...>::r_type::domain_type::rank!=0) (!clef::is_any_lazy<Args...>::value) && (indexmaps::slicer<indexmap_type,Args...>::r_type::domain_type::rank!=0) && !flags::is_const(OptionFlags)
, result_of_call_as_view<false,true,Args...> , result_of_call_as_view<false,true,Args...>
>::type // enable_if >::type // enable_if
operator()(Args const & ... args) & { operator()(Args const & ... args) & {
@ -236,8 +238,7 @@ namespace triqs { namespace arrays {
} }
/// Equivalent to make_view /// Equivalent to make_view
//typename ISPViewType<typename std::add_const<value_type>::type,domain_type::rank, OptionFlags, TraversalOrder, ViewTag >::type typename ISPViewType<value_type,domain_type::rank, OptionFlags | ConstView, TraversalOrder, ViewTag, true >::type
typename ISPViewType<value_type,domain_type::rank, OptionFlags, TraversalOrder, ViewTag, true >::type
operator()() const & { return *this; } operator()() const & { return *this; }
typename ISPViewType<value_type,domain_type::rank, OptionFlags, TraversalOrder, ViewTag, true >::type typename ISPViewType<value_type,domain_type::rank, OptionFlags, TraversalOrder, ViewTag, true >::type

View File

@ -21,13 +21,16 @@
#ifndef TRIQS_COMPILER_DETAILS_H #ifndef TRIQS_COMPILER_DETAILS_H
#define TRIQS_COMPILER_DETAILS_H #define TRIQS_COMPILER_DETAILS_H
#ifdef __GNUC__ #if defined __GNUC__ || defined __clang__
#define restrict __restrict__ #define restrict __restrict__
#endif
#if defined __GNUC__ && ! defined __clang__
#define GCC_VERSION (__GNUC__ * 10000 \ #define GCC_VERSION (__GNUC__ * 10000 \
+ __GNUC_MINOR__ * 100 \ + __GNUC_MINOR__ * 100 \
+ __GNUC_PATCHLEVEL__) + __GNUC_PATCHLEVEL__)
#if GCC_VERSION < 40801 #if GCC_VERSION < 40801
#warning "gcc compiler" GCC_VERSION
#define TRIQS_COMPILER_IS_OBSOLETE #define TRIQS_COMPILER_IS_OBSOLETE
// we still accept gcc 4.6 and 4.7, but only the 4.8.1 and higher is a compliant c++11 // we still accept gcc 4.6 and 4.7, but only the 4.8.1 and higher is a compliant c++11
#endif #endif