@@ -8,7 +8,6 @@ using Base.Order
88
99import  Base. Sort:  sort!
1010import  DataStructures:  heapify!, percolate_down!
11- import  StaticArrays:  MVector
1211
1312export  HeapSort, TimSort, RadixSort, CombSort, PagedMergeSort, ThreadedPagedMergeSort
1413
786785next_page_A (pages:: Pages ) =  Pages (pages. nextA, pages. currentNumber +  1 , pages. nextA +  1 , pages. nextB)
787786next_page_B (pages:: Pages ) =  Pages (pages. nextB, pages. currentNumber +  1 , pages. nextA, pages. nextB +  1 )
788787
789- function  next_page! (pageLocations, pages, pagesize, lo, a)
788+ Base . @propagate_inbounds   function  next_page! (pageLocations, pages, pagesize, lo, a)
790789    if  a >  pages. nextA *  pagesize +  lo
791790        pages =  next_page_A (pages)
792791    else 
@@ -796,6 +795,31 @@ function next_page!(pageLocations, pages, pagesize, lo, a)
796795    pages
797796end 
798797
798+ Base. @propagate_inbounds  function  copy_page! (v, source, offset, offset2, pagesize)
799+     for  j =  1 : pagesize
800+         v[offset +  j] =  source[offset2 +  j]
801+     end 
802+ end 
803+ 
804+ #  copy correct data into free page currentPage,
805+ #  following a permutation cycle until one page is copied from buf
806+ Base. @propagate_inbounds  function  copy_pages! (v, buf, pageLocations, currentPage, page_offset, pagesize)
807+     while  true 
808+         plc =  pageLocations[currentPage] #  page with data belonging to currentPage
809+         pageLocations[currentPage] =  0 
810+         offset =  page_offset (currentPage)
811+         if  plc >  0  #  data for currentPage is in v
812+             offset2 =  page_offset (plc)
813+             copy_page! (v, v, offset, offset2, pagesize)
814+             currentPage =  plc
815+         else  #  data for currentPage is in buf
816+             offset2 =  (- plc- 1 )* pagesize
817+             copy_page! (v, buf, offset, offset2, pagesize)
818+             return 
819+         end 
820+     end 
821+ end 
822+ 
799823#  merge v[lo:m] (A) and v[m+1:hi] (B) using buffer buf in O(sqrt(n)) space
800824function  paged_merge! (v:: AbstractVector{T} , lo:: Integer , m:: Integer , hi:: Integer , o:: Ordering , buf:: AbstractVector{T} , pageLocations:: AbstractVector{<:Integer} ) where  T
801825    @assert  lo <  m <  hi
@@ -829,7 +853,7 @@ function paged_merge!(v::AbstractVector{T}, lo::Integer, m::Integer, hi::Integer
829853        # #################
830854        #  merge the first 3 pages into buf
831855        a,b,k =  merge! ((_,_,k) ->  k<= 3 pagesize,buf,v,v,o,a,b,1 )
832-         #  initialize variable  for merging into pages
856+         #  initialize variables  for merging into pages
833857        pageLocations .=  0 
834858        pageLocations[1 : 3 ] =  - 1 : - 1 : - 3 
835859        currentPage =  0 
@@ -896,66 +920,51 @@ function paged_merge!(v::AbstractVector{T}, lo::Integer, m::Integer, hi::Integer
896920        # ########################################
897921        nFreePagesB =  nPages +  1  -  pages. nextB
898922        nFreePagesA =  3  -  nFreePagesB -  Int (partialPagePresent)
899-         freePages =  MVector {3,Int} (undef)
900-         i =  1 
901-         for  j =  0 : nFreePagesA- 1 
902-             freePages[i] =  pages. nextA +  j
903-             i +=  1 
904-         end 
905-         for  j =  0 : nFreePagesB- 1 
906-             freePages[i] =  pages. nextB +  j
907-             i +=  1 
908-         end 
909923        if  partialPagePresent
910-             freePages[i] =  pages. current
924+             #  nFreePagesA == 0 is impossible:
925+             #  the last page in A (partially in B) is always free
926+             if  nFreePagesA ==  1 
927+                 freePages =  (pages. nextA, pages. nextB, pages. current)
928+             else  #  nFreePagesA == 2
929+                 freePages =  (pages. nextA, pages. nextA +  1 , pages. current)
930+             end 
931+         else 
932+             #  nFreePagesA == 0 is impossible:
933+             #  next_page!() only uses nextA if there is MORE THAN one page free in A
934+             #  -> if there is exactly one page free in A, nextB is used
935+             #  nFreePagesA == 3 is impossible:
936+             #  B contains at least 3pagesize elements -> at least one free page will exist in B at some point
937+             #  next_page!() never uses nextB if there is more than one page free in A
938+             if  nFreePagesA ==  1 
939+                 freePages =  (pages. nextA, pages. nextB, pages. nextB +  1 )
940+             else  #  nFreePagesA == 2
941+                 freePages =  (pages. nextA, pages. nextA +  1 , pages. nextB)
942+             end 
911943        end 
912-         freePagesIndex =  3 
913-         donePageIndex =  1 
914-         #  use currentPage instead of pages.current because
915-         #  pages.nextA, pages.nextB and page.currentNumber are no longer needed
916-         currentPage =  freePages[end ]
917944        # #################
918945        #  rearrange pages
919946        # #################
947+         #  copy pages belonging to the 3 permutation chains ending with a page in the buffer
948+         for  currentPage in  freePages
949+             copy_pages! (v, buf, pageLocations, currentPage, page_offset, pagesize)
950+         end 
951+         #  copy remaining permutation cycles
952+         donePageIndex =  1 
920953        while  true 
921-             plc =  pageLocations[currentPage] #  page with data belonging to currentPage
922-             if  plc >  0 
923-                 #  data for currentPage is in v
924-                 offset =  page_offset (currentPage)
925-                 offset2 =  page_offset (plc)
926-                 for  j =  1 : pagesize
927-                     v[offset +  j] =  v[offset2 +  j]
928-                 end 
929-                 pageLocations[currentPage] =  0 
930-                 currentPage =  plc
931-             else 
932-                 #  data for currentPage is in buf
933-                 offset =  page_offset (currentPage)
934-                 offset2 =  (- plc- 1 )* pagesize
935-                 for  j =  1 : pagesize
936-                     v[offset +  j] =  buf[offset2 +  j]
937-                 end 
938-                 pageLocations[currentPage] =  0 
939-                 if  freePagesIndex >  1 
940-                     #  get next free page
941-                     freePagesIndex -=  1 
942-                     currentPage =  freePages[freePagesIndex]
943-                 else 
944-                     #  no free page remains
945-                     #  make sure that all pages are done
946-                     while  pageLocations[donePageIndex] ==  0  ||  pageLocations[donePageIndex] ==  donePageIndex
947-                         donePageIndex +=  1 
948-                         donePageIndex ==  nPages &&  return 
949-                     end 
950-                     #  copy misplaced page into buf and continue
951-                     currentPage =  pageLocations[donePageIndex]
952-                     offset =  page_offset (currentPage)
953-                     for  j =  1 : pagesize
954-                         buf[j] =  v[offset +  j]
955-                     end 
956-                     pageLocations[donePageIndex] =  - 1 
957-                 end 
954+             #  linear scan through pageLocations to make sure no cycle is missed
955+             while  pageLocations[donePageIndex] ==  0  ||  pageLocations[donePageIndex] ==  donePageIndex
956+                 donePageIndex +=  1 
957+                 donePageIndex ==  nPages &&  return 
958+             end 
959+             #  copy misplaced page into buf
960+             #  and follow the cycle starting with the newly freed page
961+             currentPage =  pageLocations[donePageIndex]
962+             offset =  page_offset (currentPage)
963+             for  j =  1 : pagesize
964+                 buf[j] =  v[offset +  j]
958965            end 
966+             pageLocations[donePageIndex] =  - 1 
967+             copy_pages! (v, buf, pageLocations, currentPage, page_offset, pagesize)
959968        end 
960969    end 
961970end 
0 commit comments