1- #! Inspired by original code (MIT license) written in 2016 by Keurfon Luu (keurfonluu@outlook.com)
2- #! https://github.com/keurfonluu/Forlab/blob/master/src/lib/forlab.f90#L2673
1+ !> Inspired by original code (MIT license) written in 2016 by Keurfon Luu (keurfonluu@outlook.com)
2+ !> https://github.com/keurfonluu/Forlab
33
44#:include "common.fypp"
55#:set RI_KINDS_TYPES = REAL_KINDS_TYPES + INT_KINDS_TYPES
@@ -9,16 +9,15 @@ submodule (stdlib_math) stdlib_math_diff
99
1010contains
1111
12- #! `diff` computes differences of adjacent elements of an array of the ${t1}$ type .
12+ !> `diff` computes differences of adjacent elements of an array.
1313
1414 #:for k1, t1 in RI_KINDS_TYPES
1515 pure module function diff_1_${k1}$(x, n, prepend, append) result(y)
1616 ${t1}$, intent(in) :: x(:)
1717 integer, intent(in), optional :: n
1818 ${t1}$, intent(in), optional :: prepend(:), append(:)
1919 ${t1}$, allocatable :: y(:)
20- integer :: size_prepend, size_append, size_x
21- ${t1}$, allocatable :: work(:)
20+ integer :: size_prepend, size_append, size_x, size_work
2221 integer :: n_, i
2322
2423 n_ = optval(n, 1)
@@ -32,22 +31,31 @@ contains
3231 if (present(prepend)) size_prepend = size(prepend)
3332 if (present(append)) size_append = size(append)
3433 size_x = size(x)
34+ size_work = size_x + size_prepend + size_append
3535
36- if (size_x + size_prepend + size_append <= n_) then
36+ if (size_work <= n_) then
3737 allocate(y(0))
3838 return
3939 end if
4040
41- allocate(work(size_x + size_prepend + size_append))
41+ !> Use a quick exit for the common case, to avoid memory allocation.
42+ if (size_prepend == 0 .and. size_append == 0 .and. n_ == 1) then
43+ y = x(2:) - x(1:size_x-1)
44+ return
45+ end if
46+
47+ block
48+ ${t1}$ :: work(size_work)
4249 if (size_prepend > 0) work(:size_prepend) = prepend
4350 work(size_prepend+1:size_prepend+size_x) = x
4451 if (size_append > 0) work(size_prepend+size_x+1:) = append
4552
4653 do i = 1, n_
47- work(1:size(work) -i) = work(2:size(work) -i+1) - work(1:size(work) -i)
54+ work(1:size_work -i) = work(2:size_work -i+1) - work(1:size_work -i)
4855 end do
49-
50- y = work(1:size(work)-n_)
56+
57+ y = work(1:size_work-n_)
58+ end block
5159
5260 end function diff_1_${k1}$
5361
@@ -56,9 +64,8 @@ contains
5664 integer, intent(in), optional :: n, dim
5765 ${t1}$, intent(in), optional :: prepend(:, :), append(:, :)
5866 ${t1}$, allocatable :: y(:, :)
59- integer :: size_prepend, size_append, size_x
67+ integer :: size_prepend, size_append, size_x, size_work
6068 integer :: n_, dim_, i
61- ${t1}$, allocatable :: work(:, :)
6269
6370 n_ = optval(n, 1)
6471 if (n_ <= 0) then
@@ -81,33 +88,48 @@ contains
8188 if (present(prepend)) size_prepend = size(prepend, dim_)
8289 if (present(append)) size_append = size(append, dim_)
8390 size_x = size(x, dim_)
91+ size_work = size_x + size_prepend + size_append
8492
85- if (size_x + size_prepend + size_append <= n_) then
93+ if (size_work <= n_) then
8694 allocate(y(0, 0))
8795 return
8896 end if
8997
98+ !> Use a quick exit for the common case, to avoid memory allocation.
99+ if (size_prepend == 0 .and. size_append == 0 .and. n_ == 1) then
100+ if (dim_ == 1) then
101+ y = x(2:, :) - x(1:size_x-1, :)
102+ elseif (dim_ == 2) then
103+ y = x(:, 2:) - x(:, 1:size_x-1)
104+ end if
105+ return
106+ end if
107+
90108 if (dim_ == 1) then
91- allocate(work(size_x+size_prepend+size_append, size(x, 2)))
109+ block
110+ ${t1}$ :: work(size_work, size(x, 2))
92111 if (size_prepend > 0) work(1:size_prepend, :) = prepend
93112 work(size_prepend+1:size_x+size_prepend, :) = x
94113 if (size_append > 0) work(size_x+size_prepend+1:, :) = append
95114 do i = 1, n_
96- work(1:size(work,1) -i, :) = work(2:size(work) -i+1, :) - work(1:size(x, 1) -i, :)
115+ work(1:size_work -i, :) = work(2:size_work -i+1, :) - work(1:size_work -i, :)
97116 end do
98117
99- y = work(1:size(work)-n_, :)
118+ y = work(1:size_work-n_, :)
119+ end block
100120
101121 elseif (dim_ == 2) then
102- allocate(work(size(x, 1), size_x+size_prepend+size_append))
122+ block
123+ ${t1}$ :: work(size(x, 1), size_work)
103124 if (size_prepend > 0) work(:, 1:size_prepend) = prepend
104125 work(:, size_prepend+1:size_x+size_prepend) = x
105126 if (size_append > 0) work(:, size_x+size_prepend+1:) = append
106127 do i = 1, n_
107- work(:, 1:size(work,2) -i) = work(:, 2:size(work,2) -i+1) - work(:, 1:size(work, 2) -i)
128+ work(:, 1:size_work -i) = work(:, 2:size_work -i+1) - work(:, 1:size_work -i)
108129 end do
109130
110- y = work(:, 1:size(work,2)-n_)
131+ y = work(:, 1:size_work-n_)
132+ end block
111133
112134 end if
113135
0 commit comments