Following "@IanH" suggestion, I implemented a wrapper which only has pointers to indices and data and everything is done IN PLACE so this should be expected to be more appropriate for large data. For small data set, I think "@Vladimir F" idea of vector indexing is better and more readable. The following code passed valgrind full memleak test and I tried for large data set (6GB double precision) and it doesn't copy data.
module any_stride
implicit none
private
! ------------------------------------------------------------
! data = pointer to the contiguous 1D double precision array
! indx = pointer to the non-uniform indices
! example: for a stride where:
! stride%data => (/ 1.0d0, 2.0d0, 3.0d0, 4.0d0 /)
! stride%indx => (/ 1, 4 /)
! is a wrapper around 1d data array with four elements
! that only elements 1 and 4 are visible to the outside world
!
type stride
private
real*8, dimension(:), pointer, public :: data => null()
integer, dimension(:), pointer, public :: indx => null()
contains
procedure :: assgn_from_scalar
procedure :: assgn_from_array
! ...
! ...
! ... add more overloaded procs if you want
generic :: assignment(=) => assgn_from_scalar &
, assgn_from_array
generic :: operator(+) => add_to_scalar &
, add_to_array
! ...
! ...
! ... add more overloaded procs if you want
end type stride
public :: stride
contains
subroutine assgn_from_scalar(this, rhs)
implicit none
class(stride), intent(inout) :: this
real*8, intent(in) :: rhs
! local vars
integer :: i
do i = 1, size(this%indx)
this%data(this%indx(i)) = rhs
end do
! done here
end subroutine assgn_from_scalar
subroutine assgn_from_array(this, rhs)
implicit none
class(stride), intent(inout) :: this
real*8, dimension(:), intent(in) :: rhs
! local vars
integer :: i
do i = 1, size(this%indx)
this%data(this%indx(i)) = rhs(i)
end do
! done here
end subroutine assgn_from_array
function add_to_scalar(lhs, rhs)
implicit none
class(stride), intent(in), target :: lhs
real*8, intent(in) :: rhs
class(stride), pointer :: add_to_scalar
! local vars
integer :: i
do i = 1, size(lhs%indx)
lhs%data(lhs%indx(i)) = lhs%data(lhs%indx(i)) + rhs
end do
add_to_scalar => lhs
! done here
end function add_to_scalar
function add_to_array(lhs, rhs)
implicit none
class(stride), intent(in), target :: lhs
real*8, dimension(:), intent(in) :: rhs
class(stride), pointer :: add_to_array
! local vars
integer :: i
do i = 1, size(lhs%indx)
lhs%data(lhs%indx(i)) = lhs%data(lhs%indx(i)) + rhs(i)
end do
add_to_array => lhs
! done here
end function add_to_array
end module any_stride
! a little tester program
!
! COMMENT and UNCOMMENT after this line
! when using the module in this file
!
program test
use any_stride
implicit none
! local vars
integer :: i
real*8, dimension(4), target :: data
real*8, dimension(2) :: rhs = (/ 3.0d0, 6.0d0 /)
integer, dimension(2), target :: indx
type(stride) :: astride
data = (/ 1.0d0, 2.0d0, 3.0d0, 4.0d0 /)
indx = (/ 1, 4 /)
astride = stride(data, indx)
astride = astride + rhs
print *, 'astride data= ', astride%data
! done here
end program test
the values 1 and 4 are only added to the first and the last entries of array data.