Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 104 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,31 +15,93 @@ on:
- 'README.md'
workflow_dispatch:

env:
# Modify this variable to change the ifx compiler version - do NOT hardcode the version
# anywhere else!
INTEL_ONEAPI_VERSION: 2025.2

jobs:
test:
if: "!contains(github.event.head_commit.message, 'skip ci')"
name: ${{ matrix.os }} - ${{ github.event_name }}
name: ${{ matrix.os_name }} - ${{ matrix.compiler }} - ${{ matrix.test_type }} - ${{ github.event_name }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
# Linux
- os: ubuntu-22.04
os_name: linux
compiler: gfortran-10
cmake_generator: Unix Makefiles
shell: bash
- os: ubuntu-latest
test_type: regular
coverage: true
- os: ubuntu-22.04
os_name: linux
compiler: gfortran-10
cmake_generator: Unix Makefiles
shell: bash
test_type: valgrind
coverage: false
- os: ubuntu-24.04
os_name: linux
compiler: gfortran-13
cmake_generator: Unix Makefiles
shell: bash
test_type: regular
coverage: false
- os: ubuntu-24.04
os_name: linux
compiler: gfortran-13
cmake_generator: Unix Makefiles
shell: bash
test_type: valgrind
coverage: false
- os: ubuntu-26.04
os_name: linux
compiler: gfortran-15
cmake_generator: Unix Makefiles
shell: bash
test_type: regular
coverage: false
- os: ubuntu-26.04
os_name: linux
compiler: gfortran-15
cmake_generator: Unix Makefiles
shell: bash
test_type: valgrind
coverage: false
- os: ubuntu-latest
os_name: linux
compiler: ifx
cmake_generator: Unix Makefiles
shell: bash
test_type: regular
coverage: false
# macOS
- os: macos-latest
os_name: macos
compiler: gfortran-13
cmake_generator: Unix Makefiles
shell: bash
test_type: regular
coverage: false
- os: macos-latest
os_name: macos
compiler: gfortran-15
cmake_generator: Unix Makefiles
shell: bash
test_type: regular
coverage: false
# Windows
- os: windows-latest
os_name: windows
compiler: gfortran
cmake_generator: MinGW Makefiles
shell: 'msys2 {0}'
test_type: regular
coverage: false
# Set default shell as suggested here: https://github.community/t/setting-default-shell-or-other-step-metadata-conditionally-in-workflows/154055
defaults:
run:
Expand All @@ -55,6 +117,35 @@ jobs:
with:
update: true
install: git base-devel mingw-w64-x86_64-toolchain mingw-w64-x86_64-gcc-fortran mingw-w64-x86_64-cmake
- uses: actions/cache@v6
if: matrix.compiler == 'ifx'
id: cache
with:
path: /opt/intel/oneapi
key: ${{ matrix.os }}-${{ matrix.compiler }}-${{ env.INTEL_ONEAPI_VERSION }}
- name: Install Intel oneAPI Fortran compiler
if: matrix.compiler == 'ifx' && steps.cache.outputs.cache-hit != 'true'
run: |
# download the key to system keyring
wget -O- https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB \
| gpg --dearmor | sudo tee /usr/share/keyrings/oneapi-archive-keyring.gpg > /dev/null

# add signed entry to apt sources and configure the APT client to use Intel repository:
echo "deb [signed-by=/usr/share/keyrings/oneapi-archive-keyring.gpg] https://apt.repos.intel.com/oneapi all main" | sudo tee /etc/apt/sources.list.d/oneAPI.list

# update package index and install Fortran compiler
sudo apt update
sudo apt-get install intel-oneapi-compiler-fortran-$INTEL_ONEAPI_VERSION

# set environment variables and make them persistent across steps
. /opt/intel/oneapi/setvars.sh
env | grep oneapi >> $GITHUB_ENV
- name: Use existing Intel oneAPI Fortran compiler
if: matrix.compiler == 'ifx' && steps.cache.outputs.cache-hit == 'true'
run: |
# set environment variables and make them persistent across steps
. /opt/intel/oneapi/setvars.sh
env | grep oneapi >> $GITHUB_ENV
- name: Verify CMake build
run: |
mkdir build && cd build
Expand All @@ -71,25 +162,33 @@ jobs:
cd TestSuiteBuild
make -j 2 FC=${{ matrix.compiler }}
- name: Run tests
if: ${{ matrix.test_type == 'regular' }}
run: |
cd TestSuiteBuild
./runSuite
- name: Run memory checks with Valgrind (only Linux)
if: ${{ matrix.os_name == 'linux' && matrix.test_type == 'valgrind' }}
run: |
sudo apt update
sudo apt-get install -y valgrind
cd TestSuiteBuild
valgrind --error-exitcode=1 -s ./runSuite
- name: Run tests for coverage
if: ${{ matrix.os == 'ubuntu-latest' }}
if: ${{ matrix.coverage }}
run: |
sudo apt-get install -y lcov
cd TestSuiteBuild
FC=${{ matrix.compiler }} ./createcoverage
- uses: codecov/codecov-action@v7
if: ${{ matrix.os == 'ubuntu-latest' }}
if: ${{ matrix.coverage }}
with:
files: ./TestSuiteBuild/lcov.info
flags: unittests
name: codecov-umbrella
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} # now required for public repos
- name: Coveralls
if: ${{ matrix.os == 'ubuntu-latest' }}
if: ${{ matrix.coverage }}
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
Expand Down
6 changes: 5 additions & 1 deletion Docs/News.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# News

July 29, 2026

FTOL now has two versions, as necessary for procedures that need to distinguish between objects declared as TYPE and those declared as CLASS. See the documentation and the tests for examples.

May 11, 2025

The stringValue() and stringValueForKey() functions now use allocated strings, so the requestedLength argument is no longer necessary. Existing code can continue to use the older versions, but those versions are deprecated and undocumented.
The stringValue() and stringValueForKey() functions now use allocated strings, so the requestedLength argument is no longer necessary. Existing code can continue to use the older versions, but those versions are deprecated and undocumented.
35 changes: 21 additions & 14 deletions Docs/UsersGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,13 +105,13 @@ added to the dictionary.
CALL v % initWithValue(3.14159)
obj => v
CALL dict % addObjectForKey(obj,``Pi'')
CALL releaseFTValue(v)
CALL releaseFTValueClass(v)

ALLOCATE(v)
CALL v % initWithValue(``Ratio of circumference to diameter'')
obj => v
CALL dict % addObjectForKey(obj,"definition")
CALL releaseFTValue(v)
CALL releaseFTValueClass(v)
END SUBROUTINE constructDictionary

Notice that in the subroutine we have allocated memory for the
Expand All @@ -125,7 +125,7 @@ later through the dictionary. This is where a systematic approach to
memory management comes in. When we allocate and initialize an object,
we assume ownership of it. When we add it to the dictionary, it assumes
partial ownership. So instead of deallocating the two value objects, we
relinquish ownership by way of the releaseFTValue() procedure, leaving
relinquish ownership by way of the releaseFTValueClass() procedure, since v is typed by CLASS, leaving
only the dictionary to be responsible for deallocating them when it does
not need them any more.

Expand All @@ -141,7 +141,7 @@ We use the dictionary as shown in the next snippet of code:

v => valueFromObject(dict % objectForKey(``definition''))
PRINT *, "The num pi = ", pi," is defined as", TRIM(v % stringValue())
CALL releaseFTDictionary(dict)
CALL releaseFTDictionaryClass(dict)

In this snippet, the values for the two keys "Pi" and "definition" are
retrieved and then used.
Expand Down Expand Up @@ -183,8 +183,8 @@ Ownership rules are as follows:
creates (allocates and initializes) it.

- When you no longer need an object (or are going out of scope) you must
release it using the releaseXXX() subroutine, where XXX refers to the
specific name of the extended type.
release it using the releaseXXX() subroutine, or releaseXXXClass(), where XXX refers to the
specific name of the extended type, depending on whether the object is declared by TYPE or CLASS.

- You must neither relinquish ownership, nor deallocate a pointer object
that you do not own.
Expand Down Expand Up @@ -212,13 +212,13 @@ the point object to the linked list.

obj => pnt
CALL list % add(obj) !list also owns pnt
CALL releasePoint(pnt) ! main gives up ownership to pnt
CALL releasePointClass(pnt) ! main gives up ownership to pnt
.
.
.
! we're done with the list, it will deallocate pnt since the list is the last owner.
! It will also deallocate itself since main is the last owner.
CALL releaseFTLinkedList(list)
CALL releaseFTLinkedListClass(list)

END PROGRAM main

Expand Down Expand Up @@ -371,9 +371,7 @@ cascading of what is stored in the object.

The release subroutine will call the base class releaseFTObject which
will, in turn, release all objects that it owns. If the object itself is
no longer referenced, it will deallocate itself. If the subclass is
going to be subclassed again, use the CLASS specifier, otherwise, we
TYPE to work only on that specific subclass.
no longer referenced, it will deallocate itself. Due to fortran's rules, create one as below with the pointer TYPEed, and another with CLASS, usually with the word Class appended, e.g. releaseXXXClass(self).

SUBROUTINE releaseSubclass(self)
IMPLICIT NONE
Expand Down Expand Up @@ -433,7 +431,8 @@ character. (To Add: complex)

- Destruction

CALL releaseFTValue(r) !For Pointers
CALL releaseFTValue(r) !For Pointers
CALL releaseFTValueClass(r) !For Pointers typed by CLASS

- Accessors

Expand Down Expand Up @@ -573,6 +572,7 @@ inherits from FTObjectClass.
- Destruction

CALL releaseFTLinkedList(list) ! If list is a pointer
CALL releaseFTLinkedListClass(list) ! If list is a pointer typed by CLASS

### FTLinkedListIterator

Expand Down Expand Up @@ -630,7 +630,8 @@ stepping through (iterating) a linked list to access its entries.

- Destruction

CALL releaseFTLinkedListIterator(iterator) ! If a pointer
CALL releaseFTLinkedListIterator(iterator) ! If a pointer
CALL releaseFTLinkedListIteratorClass(iterator)! If a pointer typed by CLASS

## Stacks

Expand All @@ -655,7 +656,8 @@ stack, for instance.

- Destruction

CALL releaseFTStack(stack) ! If stack is a pointer
CALL releaseFTStack(stack) ! If stack is a pointer
CALL releaseFTStackClass(stack)! If stack is a pointer typed by CLASS

- Pushing an object onto the stack

Expand Down Expand Up @@ -708,6 +710,7 @@ be efficient, it adds more than one entry at a time given by the
- Destruction

CALL releaseFTMutableObjectArray(array) !If array is a pointer
CALL releaseFTMutableObjectArray(array) !If array is a pointer and CLASS

- Adding an object

Expand Down Expand Up @@ -815,6 +818,7 @@ initialize the matrix with the number of rows.
- Destruction

CALL releaseFTSparseMatrix(matrix) !If matrix is a pointer
CALL releaseFTSparseMatrixClass(matrix) !If matrix is a pointer typed by CLASS

- Adding an object

Expand Down Expand Up @@ -854,6 +858,7 @@ another element.
- Destruction

CALL releaseFTMultiIndexTable(table) !If table is a pointer
CALL releaseFTMultiIndexTableClass(table) !If table is a pointer typed by CLASS

- Adding an object

Expand Down Expand Up @@ -900,6 +905,7 @@ retrieve FTValue objects.
- Destruction

CALL releaseFTDictionary(dict) !If dict is a pointer
CALL releaseFTDictionaryClass(dict) !If dict is a pointer typed by CLASS

- Adding a key-object pair

Expand Down Expand Up @@ -1002,6 +1008,7 @@ FTDICT\_KWD\_STRING\_LENGTH or less.
- Destruction

CALL releaseFTStringSet(set) !If set is a pointer
CALL releaseFTStringSetClass(set) !If set is a pointer typed by CLASS

- Adding a string

Expand Down
14 changes: 14 additions & 0 deletions Source/FTObjects/FTDataClass.f90
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,20 @@ SUBROUTINE releaseFTData(self)
CALL release(obj)
IF(.NOT.ASSOCIATED(obj)) self => NULL()
END SUBROUTINE releaseFTData
!
!////////////////////////////////////////////////////////////////////////
!
SUBROUTINE releaseFTDataClass(self)
IMPLICIT NONE
CLASS(FTData) , POINTER :: self
CLASS(FTObject), POINTER :: obj

IF(.NOT. ASSOCIATED(self)) RETURN

obj => self
CALL release(obj)
IF(.NOT.ASSOCIATED(obj)) self => NULL()
END SUBROUTINE releaseFTDataClass
!@mark -
!
!////////////////////////////////////////////////////////////////////////
Expand Down
28 changes: 28 additions & 0 deletions Source/FTObjects/FTDictionaryClass.f90
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,20 @@ SUBROUTINE releaseFTKeyObjectPair(self)
CALL release(obj)
IF(.NOT.ASSOCIATED(obj)) self => NULL()
END SUBROUTINE releaseFTKeyObjectPair
!!
!!////////////////////////////////////////////////////////////////////////

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this routine be removed?

!!
! SUBROUTINE releaseFTKeyObjectPairClass(self)
! IMPLICIT NONE
! CLASS(FTKeyObjectPair), POINTER :: self
! CLASS(FTObject) , POINTER :: obj
!
! IF(.NOT. ASSOCIATED(self)) RETURN
!
! obj => self
! CALL release(obj)
! IF(.NOT.ASSOCIATED(obj)) self => NULL()
! END SUBROUTINE releaseFTKeyObjectPairClass
!
!////////////////////////////////////////////////////////////////////////
!
Expand Down Expand Up @@ -316,6 +330,20 @@ SUBROUTINE releaseFTDictionary(self)
END SUBROUTINE releaseFTDictionary
!
!////////////////////////////////////////////////////////////////////////
!
SUBROUTINE releaseFTDictionaryClass(self)
IMPLICIT NONE
CLASS(FTDictionary) , POINTER :: self
CLASS(FTObject) , POINTER :: obj

IF(.NOT. ASSOCIATED(self)) RETURN

obj => self
CALL release(obj)
IF(.NOT.ASSOCIATED(obj)) self => NULL()
END SUBROUTINE releaseFTDictionaryClass
!
!////////////////////////////////////////////////////////////////////////
!
SUBROUTINE destructFTDictionary(self)
IMPLICIT NONE
Expand Down
Loading
Loading