Skip to content

Commit

Permalink
improved series algorithm efficiency (now up to ~5x faster and ~2.3x …
Browse files Browse the repository at this point in the history
…lighter than the previous one)
  • Loading branch information
ddnexus committed Apr 19, 2021
1 parent 1051e6d commit e17d294
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 17 deletions.
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -18,7 +18,7 @@ Pagy is the ultimate pagination gem that outperforms the others in each and ever
- __This version requires `ruby 3.0+`. For `ruby <3.0` use `pagy <4.0` (see the [pagy3 branch](https://github.com/ddnexus/pagy/tree/pagy3))__
- Updating `pagy` from `3.0+` to `4.0+` requires a single renaming in your code, but only if it uses the `searchkick` or the `elasticsearch_rails` extras (see the [Changelog](https://github.com/ddnexus/pagy/blob/master/CHANGELOG.md))
- Added the docker development environment to ease contributions
- Big code restyling following ruby 3.0 syntax and cops; tried to make the code simpler, more readable and verbose with almost negligible performance loss.
- Big code restyling following ruby 3.0 syntax and cops; the code is simpler, more readable and verbose with yet improved performance.

## Comparison with other gems

Expand Down
35 changes: 19 additions & 16 deletions lib/pagy.rb
Expand Up @@ -33,10 +33,10 @@ def initialize(vars)
if @page > @last

@offset = @items * (@page - 1) + @outset
@items = @count - ((@pages-1) * @items) if @page == @last && @count.positive?
@items = @count - ((@pages - 1) * @items) if @page == @last && @count.positive?
@from = @count.zero? ? 0 : @offset + 1 - @outset
@to = @count.zero? ? 0 : @offset + @items - @outset
@prev = (@page-1 unless @page == 1)
@prev = (@page - 1 unless @page == 1)
@next = @page == @last ? (1 if @vars[:cycle]) : @page + 1
end

Expand All @@ -45,22 +45,25 @@ def series(size=@vars[:size])
return [] if size.empty?
raise VariableError.new(self), "expected 4 items >= 0 in :size; got #{size.inspect}" \
unless size.size == 4 && size.all?{ |num| num >= 0 rescue false } # rubocop:disable Style/RescueModifier

# This algorithm is up to ~5x faster and ~2.3x lighter than the previous one (pagy < 4.3)
left_gap_start = 1 + size[0]
left_gap_end = @page - size[1] - 1
right_gap_start = @page + size[2] + 1
right_gap_end = @last - size[3]
left_gap_end = right_gap_end if left_gap_end > right_gap_end
right_gap_start = left_gap_start if left_gap_start > right_gap_start
series = []
[ *0..size[0], # initial pages from 0
*@page-size[1]..@page+size[2], # around current page
*@last-size[3]+1..@last+1 # final pages till @last+1
].sort!.each_cons(2) do |left, right| # sort and loop by 2
next if left.negative? || left == right # skip out of range and duplicates
break if left > @last # break if out of @last boundary
case right
when left+1 then series.push(left) # no gap -> no additions
when left+2 then series.push(left, left+1) # 1 page gap -> fill with missing page
else series.push(left, :gap) # n page gap -> add gap
end
start = 1
if (left_gap_end - left_gap_start).positive?
series.push(*start..(left_gap_start - 1), :gap)
start = left_gap_end + 1
end
if (right_gap_end - right_gap_start).positive?
series.push(*start..(right_gap_start - 1), :gap)
start = right_gap_end + 1
end
series.shift # shift the start boundary (0)
series[series.index(@page)] = @page.to_s # convert the current page to String
series.push(*start..@last)
series[series.index(@page)] = @page.to_s
series
end

Expand Down

0 comments on commit e17d294

Please sign in to comment.