Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Format #111

Merged
merged 5 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
8 changes: 8 additions & 0 deletions .JuliaFormatter.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Use SciML style: https://github.com/SciML/SciMLStyle
style = "sciml"

# Python style alignment. See https://github.com/domluna/JuliaFormatter.jl/pull/732.
yas_style_nesting = true

# Align struct fields for better readability of large struct definitions
align_struct_field = true
38 changes: 38 additions & 0 deletions .github/workflows/FormtatCheck.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: format-check

on:
push:
branches:
- 'main'
tags: '*'
pull_request:

jobs:
check-format:
runs-on: ${{ matrix.os }}
strategy:
matrix:
julia-version: [1]
julia-arch: [x86]
os: [ubuntu-latest]
steps:
- uses: julia-actions/setup-julia@latest
with:
version: ${{ matrix.julia-version }}

- uses: actions/checkout@v4
JoshuaLampert marked this conversation as resolved.
Show resolved Hide resolved
- name: Install JuliaFormatter and format
run: |
julia -e 'using Pkg; Pkg.add(PackageSpec(name = "JuliaFormatter"))'
julia -e 'using JuliaFormatter; format(["src/P4est.jl", "src/pointerwrappers.jl", "test"])'
- name: Format check
run: |
julia -e '
out = Cmd(`git diff --name-only`) |> read |> String
if out == ""
exit(0)
else
@error "Some files have not been formatted !!!"
write(stdout, out)
exit(1)
end'
7 changes: 2 additions & 5 deletions src/P4est.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ using UUIDs: UUID
const _PREFERENCE_LIBP4EST = @load_preference("libp4est", "P4est_jll")
const _PREFERENCE_LIBSC = @load_preference("libsc", _PREFERENCE_LIBP4EST)


# Include p4est bindings
include("LibP4est.jl")
@reexport using .LibP4est
Expand All @@ -20,7 +19,6 @@ include("LibP4est.jl")
include("pointerwrappers.jl")
@reexport using .PointerWrappers: PointerWrapper


# Higher-level API defined in P4est.jl
"""
P4est.uses_mpi()
Expand Down Expand Up @@ -109,7 +107,8 @@ path_sc_library() = _PREFERENCE_LIBSC
Returns `false` if a system-provided MPI installation is set via the MPIPreferences, but
not a system-provided `p4est` installation. In this case, P4est.jl is not usable.
"""
preferences_set_correctly() = !(_PREFERENCE_LIBP4EST == "P4est_jll" && MPIPreferences.binary == "system")
preferences_set_correctly() = !(_PREFERENCE_LIBP4EST == "P4est_jll" &&
MPIPreferences.binary == "system")

"""
P4est.init(log_handler, log_threshold)
Expand All @@ -134,7 +133,6 @@ function init(log_handler, log_threshold)
return nothing
end


function __init__()
# If a system-provided MPI installation with default p4est version is used, we cannot execute `P4est.version()`
# because the p4est functions are not available
Expand All @@ -151,5 +149,4 @@ function __init__()
return nothing
end


end
73 changes: 43 additions & 30 deletions src/pointerwrappers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -37,62 +37,75 @@ julia> p4est_pw.connectivity.num_trees[]
```
"""
struct PointerWrapper{T}
pointer::Ptr{T}
pointer::Ptr{T}
end

# Non-pointer-type fields get wrapped as a normal PointerWrapper
PointerWrapper(::Type{T}, pointer) where T = PointerWrapper{T}(pointer)
PointerWrapper(::Type{T}, pointer) where {T} = PointerWrapper{T}(pointer)

# Pointer-type fields get dereferenced such that PointerWrapper wraps the pointer to the field type
PointerWrapper(::Type{Ptr{T}}, pointer) where T = PointerWrapper{T}(unsafe_load(Ptr{Ptr{T}}(pointer)))
function PointerWrapper(::Type{Ptr{T}}, pointer) where {T}
PointerWrapper{T}(unsafe_load(Ptr{Ptr{T}}(pointer)))
end

# Cannot use `pw.pointer` since we implement `getproperty` to return the fields of `T` itself
Base.pointer(pw::PointerWrapper{T}) where T = getfield(pw, :pointer)
Base.pointer(pw::PointerWrapper{T}) where {T} = getfield(pw, :pointer)
# Allow passing a `PointerWrapper` to wrapped C functions
Base.unsafe_convert(::Type{Ptr{T}}, pw::PointerWrapper{T}) where {T} = Base.unsafe_convert(Ptr{T}, pointer(pw))
function Base.unsafe_convert(::Type{Ptr{T}}, pw::PointerWrapper{T}) where {T}
Base.unsafe_convert(Ptr{T}, pointer(pw))
end

# Syntactic sugar
Base.propertynames(::PointerWrapper{T}) where T = fieldnames(T)
Base.propertynames(::PointerWrapper{T}) where {T} = fieldnames(T)

# Syntactic sugar: allows one to use `pw.fieldname` to get a PointerWrapper-wrapped pointer to `fieldname`
function Base.getproperty(pw::PointerWrapper{T}, name::Symbol) where T
i = findfirst(isequal(name), fieldnames(T))
if isnothing(i)
# For some `struct`s, `fieldnames` gives `data` and not the actual field names, but we can use `Base.getproperty` for pointers,
# see https://github.com/trixi-framework/P4est.jl/issues/72
return PointerWrapper(Base.getproperty(pointer(pw), name))
end

return PointerWrapper(fieldtype(T, i), pointer(pw) + fieldoffset(T, i))
function Base.getproperty(pw::PointerWrapper{T}, name::Symbol) where {T}
i = findfirst(isequal(name), fieldnames(T))
if isnothing(i)
# For some `struct`s, `fieldnames` gives `data` and not the actual field names, but we can use `Base.getproperty` for pointers,
# see https://github.com/trixi-framework/P4est.jl/issues/72
return PointerWrapper(Base.getproperty(pointer(pw), name))
end

return PointerWrapper(fieldtype(T, i), pointer(pw) + fieldoffset(T, i))
end

# Syntactic sugar: allows one to use `pw.fieldname` to set `fieldname`
function Base.setproperty!(pw::PointerWrapper{T}, name::Symbol, v) where T
i = findfirst(isequal(name), fieldnames(T))
if isnothing(i)
# For some `struct`s, `fieldnames` gives `data` and not the actual field names, but we can use `Base.setproperty!` for pointers,
# see https://github.com/trixi-framework/P4est.jl/issues/72 and https://github.com/trixi-framework/P4est.jl/issues/79
return Base.setproperty!(pointer(pw), name, v)
end
return unsafe_store!(reinterpret(Ptr{fieldtype(T, i)}, pointer(pw) + fieldoffset(T, i)), v)
function Base.setproperty!(pw::PointerWrapper{T}, name::Symbol, v) where {T}
i = findfirst(isequal(name), fieldnames(T))
if isnothing(i)
# For some `struct`s, `fieldnames` gives `data` and not the actual field names, but we can use `Base.setproperty!` for pointers,
# see https://github.com/trixi-framework/P4est.jl/issues/72 and https://github.com/trixi-framework/P4est.jl/issues/79
return Base.setproperty!(pointer(pw), name, v)
end
return unsafe_store!(reinterpret(Ptr{fieldtype(T, i)}, pointer(pw) + fieldoffset(T, i)),
v)
end

# `[]` allows one to access the actual underlying data and
# `[i]` allows one to access the actual underlying data of an array
Base.getindex(pw::PointerWrapper, i::Integer=1) = unsafe_load(pw, i)
Base.setindex!(pw::PointerWrapper, value, i::Integer=1) = unsafe_store!(pw, value, i)
Base.getindex(pw::PointerWrapper, i::Integer = 1) = unsafe_load(pw, i)
Base.setindex!(pw::PointerWrapper, value, i::Integer = 1) = unsafe_store!(pw, value, i)

# When `unsafe_load`ing a PointerWrapper object, we really want to load the underlying object
Base.unsafe_load(pw::PointerWrapper, i::Integer=1) = unsafe_load(pointer(pw), i)
Base.unsafe_load(pw::PointerWrapper, i::Integer = 1) = unsafe_load(pointer(pw), i)

# When `unsafe_wrap`ping a PointerWrapper object, we really want to wrap the underlying array
Base.unsafe_wrap(AType::Union{Type{Array},Type{Array{T}},Type{Array{T,N}}},
pw::PointerWrapper, dims::Union{NTuple{N,Int}, Integer}; own::Bool = false) where {T,N} = unsafe_wrap(AType, pointer(pw), dims; own)
function Base.unsafe_wrap(AType::Union{Type{Array}, Type{Array{T}}, Type{Array{T, N}}},
pw::PointerWrapper,
dims::Union{NTuple{N, Int}, Integer};
own::Bool = false,) where {T, N}
unsafe_wrap(AType, pointer(pw), dims; own)
end

# If value is of the wrong type, try to convert it
Base.unsafe_store!(pw::PointerWrapper{T}, value, i::Integer=1) where T = unsafe_store!(pw, convert(T, value), i)
function Base.unsafe_store!(pw::PointerWrapper{T}, value, i::Integer = 1) where {T}
unsafe_store!(pw, convert(T, value), i)
end

# Store value to wrapped location
Base.unsafe_store!(pw::PointerWrapper{T}, value::T, i::Integer=1) where T = unsafe_store!(pointer(pw), value, i)
function Base.unsafe_store!(pw::PointerWrapper{T}, value::T, i::Integer = 1) where {T}
unsafe_store!(pointer(pw), value, i)
end

end
18 changes: 9 additions & 9 deletions test/configure_packages.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,19 @@ rm(joinpath(dirname(@__DIR__), "LocalPreferences.toml"), force = true)

# Next, we configure MPI.jl appropriately.
@static if JULIA_P4EST_TEST == "P4EST_CUSTOM_MPI_CUSTOM"
import MPIPreferences
MPIPreferences.use_system_binary()
import MPIPreferences
MPIPreferences.use_system_binary()
end

# Finally, we configure P4est.jl as desired.
@static if JULIA_P4EST_TEST == "P4EST_CUSTOM_MPI_CUSTOM"
import UUIDs, Preferences
Preferences.set_preferences!(
UUIDs.UUID("7d669430-f675-4ae7-b43e-fab78ec5a902"), # UUID of P4est.jl
"libp4est" => JULIA_P4EST_TEST_LIBP4EST, force = true)
Preferences.set_preferences!(
UUIDs.UUID("7d669430-f675-4ae7-b43e-fab78ec5a902"), # UUID of P4est.jl
"libsc" => JULIA_P4EST_TEST_LIBSC, force = true)
import UUIDs, Preferences
Preferences.set_preferences!(UUIDs.UUID("7d669430-f675-4ae7-b43e-fab78ec5a902"), # UUID of P4est.jl
"libp4est" => JULIA_P4EST_TEST_LIBP4EST,
force = true)
Preferences.set_preferences!(UUIDs.UUID("7d669430-f675-4ae7-b43e-fab78ec5a902"), # UUID of P4est.jl
"libsc" => JULIA_P4EST_TEST_LIBSC,
force = true)
end

@info "P4est.jl tests configured" JULIA_P4EST_TEST JULIA_P4EST_TEST_LIBP4EST JULIA_P4EST_TEST_LIBSC
41 changes: 20 additions & 21 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,29 @@ using P4est
import MPIPreferences
@info "Testing P4est.jl with" MPIPreferences.binary MPIPreferences.abi


@time @testset "P4est.jl tests" begin
# For some weird reason, the MPI tests must come first since they fail
# otherwise with a custom MPI installation.
@time @testset "MPI" begin
# Do a dummy `@test true`:
# If the process errors out the testset would error out as well,
# cf. https://github.com/JuliaParallel/MPI.jl/pull/391
@test true

@info "Starting parallel tests"

mpiexec() do cmd
run(`$cmd -n 2 $(Base.julia_cmd()) --threads=1 --check-bounds=yes --project=$(dirname(@__DIR__)) $(abspath("tests_basic.jl"))`)
end
# For some weird reason, the MPI tests must come first since they fail
# otherwise with a custom MPI installation.
@time @testset "MPI" begin
# Do a dummy `@test true`:
# If the process errors out the testset would error out as well,
# cf. https://github.com/JuliaParallel/MPI.jl/pull/391
@test true

@info "Starting parallel tests"

@info "Finished parallel tests"
end
mpiexec() do cmd
run(`$cmd -n 2 $(Base.julia_cmd()) --threads=1 --check-bounds=yes --project=$(dirname(@__DIR__)) $(abspath("tests_basic.jl"))`)
end

@time @testset "serial" begin
@info "Starting serial tests"
@info "Finished parallel tests"
end

@time @testset "serial" begin
@info "Starting serial tests"

include("tests_basic.jl")
include("tests_basic.jl")

@info "Finished serial tests"
end
@info "Finished serial tests"
end
end
Loading
Loading