-
Notifications
You must be signed in to change notification settings - Fork 118
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat (memorymananger) Create iterators for the ListType and MemoryLis…
…tType (#1765) * Create iterator for the ListType and MemoryListType. Use them in the MemoryManager and MemoryManangerExt * Update mf5to6 make files * Reimplement the get method in the memorylist to use the name and path of a variable. * Extract ListNodeType to separate class. Add iterator method to the List class. * Make iterator variables allocatable * Add unit ListIterator unittests * Add unit test for the MemoryContainerIterator * Fix msvs error * Apply review comments * Fix spelling errors * Fix format errors
- Loading branch information
Showing
23 changed files
with
711 additions
and
189 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
module TestListIterator | ||
use KindModule, only: I4B | ||
use testdrive, only: error_type, unittest_type, new_unittest, check | ||
use ListNodeModule, only: ListNodeType | ||
use ListIteratorModule, only: ListIteratorType | ||
use IteratorModule, only: IteratorType | ||
|
||
implicit none | ||
private | ||
public :: collect_listiterator | ||
|
||
contains | ||
|
||
subroutine collect_listiterator(testsuite) | ||
type(unittest_type), allocatable, intent(out) :: testsuite(:) | ||
|
||
testsuite = [ & | ||
new_unittest("constructor", test_constructor), & | ||
new_unittest("iterate_through_list", test_iterate_through_list), & | ||
new_unittest("empty_list", test_empty_list) & | ||
] | ||
end subroutine collect_listiterator | ||
|
||
!> @brief Test the initial state of the iterator | ||
!! | ||
!! When the iterator is created with a non-empty list: | ||
!! - it should indicate that it has a next value | ||
!! - it should return null when retrieving the current value | ||
!< | ||
subroutine test_constructor(error) | ||
type(error_type), allocatable, intent(out) :: error | ||
!- Locals | ||
class(IteratorType), allocatable :: itr | ||
type(ListNodeType), target :: firstNode | ||
type(ListNodeType), pointer :: firstNodePtr | ||
|
||
!- Arrange. | ||
firstNodePtr => firstNode | ||
|
||
!- Act. | ||
itr = ListIteratorType(firstNodePtr) | ||
|
||
!- Assert. | ||
call check(error,.not. associated(itr%value())) | ||
if (allocated(error)) return | ||
|
||
call check(error, itr%has_next()) | ||
if (allocated(error)) return | ||
end subroutine test_constructor | ||
|
||
!> @brief Iterate through a list | ||
!! | ||
!! This test creates an iterator for a list of 3 nodes. | ||
!! It iterates though it and validates the expected values | ||
!< | ||
subroutine test_iterate_through_list(error) | ||
type(error_type), allocatable, intent(out) :: error | ||
!- Locals | ||
class(IteratorType), allocatable :: itr | ||
type(ListNodeType), pointer :: firstNodePtr | ||
|
||
type(ListNodeType), target :: firstNode | ||
type(ListNodeType), target :: secondNode | ||
type(ListNodeType), target :: thirdNode | ||
|
||
integer(I4B), target :: expected_value1 = 2 | ||
integer(I4B), target :: expected_value2 = 6 | ||
integer(I4B), target :: expected_value3 = 567 | ||
integer(I4B) :: expected_values(3) | ||
|
||
integer(I4B) :: itr_count = 0 | ||
integer(I4B), pointer :: value_ptr | ||
|
||
!- Arrange. | ||
expected_values = [expected_value1, expected_value2, expected_value3] | ||
|
||
firstNode%value => expected_value1 | ||
firstNode%nextNode => secondNode | ||
|
||
secondNode%value => expected_value2 | ||
secondNode%nextNode => thirdNode | ||
|
||
thirdNode%value => expected_value3 | ||
thirdNode%nextNode => null() | ||
|
||
firstNodePtr => firstNode | ||
itr = ListIteratorType(firstNodePtr) | ||
|
||
!- Act. | ||
do while (itr%has_next()) | ||
call itr%next() | ||
itr_count = itr_count + 1 | ||
!- Assert. | ||
select type (val => itr%value()) | ||
type is (integer(I4B)) | ||
value_ptr => val | ||
|
||
call check(error, value_ptr == expected_values(itr_count)) | ||
if (allocated(error)) return | ||
end select | ||
end do | ||
|
||
end subroutine test_iterate_through_list | ||
|
||
!> @brief Test the initial state of the iterator with an empty list | ||
!! | ||
!! When the iterator is created it with an empty list: | ||
!! - It should indicate that it has no next value | ||
!! - It should return null when retrieving the current value | ||
!< | ||
subroutine test_empty_list(error) | ||
type(error_type), allocatable, intent(out) :: error | ||
!- Locals | ||
class(IteratorType), allocatable :: itr | ||
type(ListNodeType), pointer :: firstNodePtr | ||
|
||
!- Arrange. | ||
firstNodePtr => null() | ||
|
||
!- Act. | ||
itr = ListIteratorType(firstNodePtr) | ||
|
||
!- Assert. | ||
call check(error,.not. itr%has_next()) | ||
if (allocated(error)) return | ||
|
||
call check(error,.not. associated(itr%value())) | ||
if (allocated(error)) return | ||
|
||
end subroutine test_empty_list | ||
|
||
end module TestListIterator |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
module TestMemoryContainerIterator | ||
use KindModule, only: I4B, LGP | ||
use MemoryContainerIteratorModule, only: MemoryContainerIteratorType | ||
use MemoryListModule, only: MemoryListType | ||
use MemoryTypeModule, only: MemoryType | ||
use testdrive, only: error_type, unittest_type, new_unittest, check | ||
|
||
contains | ||
subroutine collect_memorycontaineriterator(testsuite) | ||
type(unittest_type), allocatable, intent(out) :: testsuite(:) | ||
|
||
testsuite = [ & | ||
new_unittest("iterate_through_container", & | ||
test_iterate_through_container) & | ||
] | ||
end subroutine collect_memorycontaineriterator | ||
|
||
!> @brief Iterate through a MemoryContainer | ||
!! | ||
!! This test creates an iterator for a container containing 3 MemoryTypes. | ||
!! It iterates though the container and validates that each type is reached. | ||
!! | ||
!! Because the order of the iterator doesn't have to match the order in which | ||
!! the MemoryTypes have been added an 'iterated' array is used. A flag in the | ||
!! array is set to true and at the end it is validated that the entire array | ||
!! is set to to true (indicating that all memory types have been reached) | ||
!< | ||
subroutine test_iterate_through_container(error) | ||
type(error_type), allocatable, intent(out) :: error | ||
!- Locals | ||
type(MemoryListType) :: memory_container | ||
type(MemoryContainerIteratorType), allocatable :: itr | ||
|
||
type(MemoryType), target :: mt1 | ||
type(MemoryType), target :: mt2 | ||
type(MemoryType), target :: mt3 | ||
|
||
type(MemoryType), pointer :: current_mt | ||
integer(I4B) :: mt_index = 0 | ||
|
||
logical(LGP) :: iterated(3) = .false. | ||
|
||
!- Arrange. | ||
mt1%name = "TestName1" | ||
mt2%name = "TestName2" | ||
mt3%name = "TestName3" | ||
|
||
current_mt => mt1 | ||
call memory_container%add(current_mt) | ||
|
||
current_mt => mt2 | ||
call memory_container%add(current_mt) | ||
|
||
current_mt => mt3 | ||
call memory_container%add(current_mt) | ||
|
||
itr = memory_container%iterator() | ||
|
||
!- Act. | ||
current_mt => null() | ||
do while (itr%has_next()) | ||
call itr%next() | ||
current_mt => itr%value() | ||
|
||
read (current_mt%name(len_trim(current_mt%name):), '(i1)') mt_index | ||
iterated(mt_index) = .true. | ||
end do | ||
|
||
!- Assert. | ||
call check(error, all(iterated .eqv. .true.)) | ||
if (allocated(error)) return | ||
|
||
end subroutine test_iterate_through_container | ||
|
||
end module TestMemoryContainerIterator |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
module IteratorModule | ||
use KindModule, only: LGP | ||
implicit none | ||
private | ||
|
||
public :: IteratorType | ||
|
||
type, abstract :: IteratorType | ||
contains | ||
procedure(has_next_if), deferred :: has_next | ||
procedure(next_if), deferred :: next | ||
procedure(value_if), deferred :: value | ||
|
||
end type IteratorType | ||
|
||
abstract interface | ||
|
||
function has_next_if(this) result(res) | ||
import IteratorType | ||
import LGP | ||
class(IteratorType) :: this | ||
logical(LGP) :: res | ||
end function | ||
|
||
subroutine next_if(this) | ||
import IteratorType | ||
class(IteratorType) :: this | ||
end subroutine | ||
|
||
function value_if(this) result(res) | ||
import IteratorType | ||
class(IteratorType) :: this | ||
class(*), pointer :: res | ||
end function | ||
|
||
end interface | ||
|
||
end module IteratorModule |
Oops, something went wrong.