Octopus
namespace.F90
Go to the documentation of this file.
1!! Copyright (C) 2019 M. Oliveira, S. Ohlmann
2!!
3!! This Source Code Form is subject to the terms of the Mozilla Public
4!! License, v. 2.0. If a copy of the MPL was not distributed with this
5!! file, You can obtain one at https://mozilla.org/MPL/2.0/.
6!!
7
8#include "global.h"
9
10module namespace_oct_m
11 use global_oct_m
12 use mpi_oct_m
13 implicit none
14
15 private
16 public :: &
19
20 integer, parameter, public :: MAX_NAMESPACE_LEN = 128
21
22 type :: namespace_t
23 private
24 character(len=MAX_NAMESPACE_LEN) :: name = ""
25 type(namespace_t), pointer, public :: parent => null()
26 contains
27 procedure :: get => namespace_get
28 procedure :: len => namespace_len
29 generic :: operator(==) => equal
30 procedure :: equal => namespace_equal
31 procedure :: contains => namespace_contains
32 procedure :: is_contained_in => namespace_is_contained_in
33 end type namespace_t
34
35 interface namespace_t
36 procedure namespace_constructor
37 end interface namespace_t
38
39 type(namespace_t) :: global_namespace
40
41contains
42
43 !---------------------------------------------------------
48 recursive type(namespace_t) function namespace_constructor(name, parent, delimiter)
49 character(len=*), intent(in) :: name
50 type(namespace_t), optional, target, intent(in) :: parent
51 character(len=1), optional, intent(in) :: delimiter
52
53 integer :: total_len, parent_len
54 character(len=1) :: delimiter_
55
56 if (present(delimiter)) then
57 delimiter_ = delimiter
58 else
59 delimiter_ = '.'
60 end if
61
62 ! Calculate total length of namespace, including the parent
63 total_len = len_trim(name)
64 if (present(parent)) then
65 parent_len = parent%len()
66 if (parent_len > 0) then
67 total_len = total_len + parent_len + 1
68 end if
69 end if
70
71 ! If total length is too large, stop and explain the reason
72 if (total_len > max_namespace_len) then
73 write(stderr,'(a)') '*** Fatal Error (description follows)'
74 write(stderr,'(a)') 'Trying to create the following namespace:'
75 if (present(parent)) then
76 if (parent%len() > 0) then
77 write(stderr,'(a)') trim(parent%get()) // delimiter_ // name
78 end if
79 else
80 write(stderr,'(a)') name
81 end if
82 write(stderr,'(a,i4,a)') 'but namespaces are limited to ', max_namespace_len, ' characters'
83 call mpi_world%abort()
84 end if
85
86 ! We do not allow the creation of empty namespaces, as that might lead to ambiguous paths
87 assert(len_trim(name) > 0)
88
89 namespace_constructor%name = name
90 if (present(parent)) then
91 namespace_constructor%parent => parent
92 else
93 nullify(namespace_constructor%parent)
94 end if
95
96 end function namespace_constructor
97
98 ! ---------------------------------------------------------
100 !
101 recursive function namespace_get(this, delimiter) result(name)
102 class(namespace_t), intent(in) :: this
103 character(len=1), optional, intent(in) :: delimiter
104 character(len=MAX_NAMESPACE_LEN) :: name
106 character(len=1) :: delimiter_
107
108 if (present(delimiter)) then
109 delimiter_ = delimiter
110 else
111 delimiter_ = '.'
112 end if
113
114 name = this%name
115 if (associated(this%parent)) then
116 if (len_trim(name) > 0 .and. this%parent%len() > 0) then
117 name = trim(this%parent%get(delimiter_)) // delimiter_ // trim(name)
118 end if
119 end if
121 end function namespace_get
123 ! ---------------------------------------------------------
124 pure recursive function namespace_len(this)
125 class(namespace_t), intent(in) :: this
126 integer :: namespace_len
128 integer :: parent_len
129
130 namespace_len = len_trim(this%name)
131 if (associated(this%parent)) then
132 parent_len = this%parent%len()
133 if (parent_len > 0) then
134 namespace_len = namespace_len + parent_len + 1
135 end if
136 end if
137
138 end function namespace_len
139
140 ! ---------------------------------------------------------
141 elemental logical function namespace_equal(lhs, rhs)
142 class(namespace_t), intent(in) :: lhs
143 class(namespace_t), intent(in) :: rhs
144
145 namespace_equal = lhs%name == rhs%name
146
147 end function namespace_equal
148
149 ! ---------------------------------------------------------
150 logical function namespace_contains(this, namespace)
151 class(namespace_t), target, intent(in) :: this
152 type(namespace_t), target, intent(in) :: namespace
153
154 logical :: found_ancestor
155 type(namespace_t), pointer :: this_ancestor, namespace_ancestor
156
157 ! Find if there is a common ancestor
158 found_ancestor = .false.
159 namespace_ancestor => namespace
160 do while (associated(namespace_ancestor))
161 found_ancestor = namespace_ancestor == this
162 if (found_ancestor) exit
163 namespace_ancestor => namespace_ancestor%parent
164 end do
165
166 if (found_ancestor) then
167 ! Check if the remaining ancestors are also equal
169 this_ancestor => this
170 do while (associated(namespace_ancestor%parent) .and. associated(this_ancestor%parent))
171 namespace_contains = namespace_ancestor%parent == this_ancestor%parent
172 if (.not. namespace_contains) exit
173 this_ancestor => this_ancestor%parent
174 namespace_ancestor => namespace_ancestor%parent
175 end do
176 else
177 ! We did not find a common ancestor
178 namespace_contains = .false.
179 end if
180
181 end function namespace_contains
182
183 ! ---------------------------------------------------------
184 logical function namespace_is_contained_in(this, name, delimiter) result(is_contained)
185 class(namespace_t), target, intent(in) :: this
186 character(len=*), intent(in) :: name
187 character(len=1), optional, intent(in) :: delimiter
188
189 integer :: si, se
190 character(len=1) :: delimiter_
191 type(namespace_t), target :: namespace
192 type(namespace_t), pointer :: next, parent
193
194 if (present(delimiter)) then
195 delimiter_ = delimiter
196 else
197 delimiter_ = '.'
198 end if
199
200 ! Create temporary namespace from name
201 si = index(name, delimiter_, back=.true.)
202 namespace%name = name(si+1:len(name))
203 next => namespace
204 do while (si /= 0)
205 se = si
206 si = index(name(:se-1), delimiter_, back=.true.)
207 allocate(next%parent)
208 next%parent = namespace_t(name(si+1:se-1), delimiter=delimiter)
209 next => next%parent
210 end do
211
212 ! Compare namespaces
213 is_contained = namespace%contains(this)
214
215 ! Deallocate all memory
216 parent => namespace%parent
217 do while (associated(parent))
218 next => parent%parent
219 deallocate(parent)
220 parent => next
221 end do
222
223 end function namespace_is_contained_in
224
225end module namespace_oct_m
226
227!! Local Variables:
228!! mode: f90
229!! coding: utf-8
230!! End:
type(mpi_grp_t), public mpi_world
Definition: mpi.F90:272
logical function namespace_is_contained_in(this, name, delimiter)
Definition: namespace.F90:280
elemental logical function namespace_equal(lhs, rhs)
Definition: namespace.F90:237
recursive type(namespace_t) function namespace_constructor(name, parent, delimiter)
Create namespace from name. If parent is present, the new namespace will be a child of it....
Definition: namespace.F90:144
logical function namespace_contains(this, namespace)
Definition: namespace.F90:246
type(namespace_t), public global_namespace
Definition: namespace.F90:134
pure recursive integer function namespace_len(this)
Definition: namespace.F90:220
recursive character(len=max_namespace_len) function namespace_get(this, delimiter)
get full name, including parents
Definition: namespace.F90:197
int true(void)