Octopus
namespace.F90
Go to the documentation of this file.
1!! Copyright (C) 2019 M. Oliveira, S. Ohlmann
2!!
3!! This program is free software; you can redistribute it and/or modify
4!! it under the terms of the GNU General Public License as published by
5!! the Free Software Foundation; either version 2, or (at your option)
6!! any later version.
7!!
8!! This program is distributed in the hope that it will be useful,
9!! but WITHOUT ANY WARRANTY; without even the implied warranty of
10!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11!! GNU General Public License for more details.
12!!
13!! You should have received a copy of the GNU General Public License
14!! along with this program; if not, write to the Free Software
15!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16!! 02110-1301, USA.
17!!
18
19#include "global.h"
20
21module namespace_oct_m
22 use global_oct_m
23 use mpi_oct_m
24 implicit none
25
26 private
27 public :: &
30
31 integer, parameter, public :: MAX_NAMESPACE_LEN = 128
32
33 type :: namespace_t
34 private
35 character(len=MAX_NAMESPACE_LEN) :: name = ""
36 type(namespace_t), pointer, public :: parent => null()
37 contains
38 procedure :: get => namespace_get
39 procedure :: len => namespace_len
40 generic :: operator(==) => equal
41 procedure :: equal => namespace_equal
42 procedure :: contains => namespace_contains
43 procedure :: is_contained_in => namespace_is_contained_in
44 end type namespace_t
45
46 interface namespace_t
47 procedure namespace_constructor
48 end interface namespace_t
49
50 type(namespace_t) :: global_namespace
51
52contains
53
54 !---------------------------------------------------------
59 recursive type(namespace_t) function namespace_constructor(name, parent, delimiter)
60 character(len=*), intent(in) :: name
61 type(namespace_t), optional, target, intent(in) :: parent
62 character(len=1), optional, intent(in) :: delimiter
63
64 integer :: total_len, parent_len
65 character(len=1) :: delimiter_
66
67 if (present(delimiter)) then
68 delimiter_ = delimiter
69 else
70 delimiter_ = '.'
71 end if
72
73 ! Calculate total length of namespace, including the parent
74 total_len = len_trim(name)
75 if (present(parent)) then
76 parent_len = parent%len()
77 if (parent_len > 0) then
78 total_len = total_len + parent_len + 1
79 end if
80 end if
81
82 ! If total length is too large, stop and explain the reason
83 if (total_len > max_namespace_len) then
84 write(stderr,'(a)') '*** Fatal Error (description follows)'
85 write(stderr,'(a)') 'Trying to create the following namespace:'
86 if (present(parent)) then
87 if (parent%len() > 0) then
88 write(stderr,'(a)') trim(parent%get()) // delimiter_ // name
89 end if
90 else
91 write(stderr,'(a)') name
92 end if
93 write(stderr,'(a,i4,a)') 'but namespaces are limited to ', max_namespace_len, ' characters'
94#ifdef HAVE_MPI
95 if (mpi_world%comm /= -1) call mpi_abort(mpi_world%comm, 999, mpi_err)
96#endif
97 stop
98 end if
99
100 ! We do not allow the creation of empty namespaces, as that might lead to ambiguous paths
101 assert(len_trim(name) > 0)
102
103 namespace_constructor%name = name
104 if (present(parent)) then
105 namespace_constructor%parent => parent
106 else
107 nullify(namespace_constructor%parent)
108 end if
109
110 end function namespace_constructor
111
112 ! ---------------------------------------------------------
113 recursive function namespace_get(this, delimiter) result(name)
114 class(namespace_t), intent(in) :: this
115 character(len=1), optional, intent(in) :: delimiter
116 character(len=MAX_NAMESPACE_LEN) :: name
117
118 character(len=1) :: delimiter_
119
120 if (present(delimiter)) then
121 delimiter_ = delimiter
122 else
123 delimiter_ = '.'
124 end if
126 name = this%name
127 if (associated(this%parent)) then
128 if (len_trim(name) > 0 .and. this%parent%len() > 0) then
129 name = trim(this%parent%get(delimiter_)) // delimiter_ // trim(name)
130 end if
131 end if
132
133 end function namespace_get
134
135 ! ---------------------------------------------------------
136 pure recursive function namespace_len(this)
137 class(namespace_t), intent(in) :: this
138 integer :: namespace_len
139
140 integer :: parent_len
141
142 namespace_len = len_trim(this%name)
143 if (associated(this%parent)) then
144 parent_len = this%parent%len()
145 if (parent_len > 0) then
146 namespace_len = namespace_len + parent_len + 1
147 end if
148 end if
149
150 end function namespace_len
151
152 ! ---------------------------------------------------------
153 elemental logical function namespace_equal(lhs, rhs)
154 class(namespace_t), intent(in) :: lhs
155 class(namespace_t), intent(in) :: rhs
156
157 namespace_equal = lhs%name == rhs%name
158
159 end function namespace_equal
160
161 ! ---------------------------------------------------------
162 logical function namespace_contains(this, namespace)
163 class(namespace_t), target, intent(in) :: this
164 type(namespace_t), target, intent(in) :: namespace
165
166 logical :: found_ancestor
167 type(namespace_t), pointer :: this_ancestor, namespace_ancestor
168
169 ! Find if there is a common ancestor
170 found_ancestor = .false.
171 namespace_ancestor => namespace
172 do while (associated(namespace_ancestor))
173 found_ancestor = namespace_ancestor == this
174 if (found_ancestor) exit
175 namespace_ancestor => namespace_ancestor%parent
176 end do
177
178 if (found_ancestor) then
179 ! Check if the remaining ancestors are also equal
181 this_ancestor => this
182 do while (associated(namespace_ancestor%parent) .and. associated(this_ancestor%parent))
183 namespace_contains = namespace_ancestor%parent == this_ancestor%parent
184 if (.not. namespace_contains) exit
185 this_ancestor => this_ancestor%parent
186 namespace_ancestor => namespace_ancestor%parent
187 end do
188 else
189 ! We did not find a common ancestor
190 namespace_contains = .false.
191 end if
192
193 end function namespace_contains
194
195 ! ---------------------------------------------------------
196 logical function namespace_is_contained_in(this, name, delimiter) result(is_contained)
197 class(namespace_t), target, intent(in) :: this
198 character(len=*), intent(in) :: name
199 character(len=1), optional, intent(in) :: delimiter
200
201 integer :: si, se
202 character(len=1) :: delimiter_
203 type(namespace_t), target :: namespace
204 type(namespace_t), pointer :: next, parent
205
206 if (present(delimiter)) then
207 delimiter_ = delimiter
208 else
209 delimiter_ = '.'
210 end if
211
212 ! Create temporary namespace from name
213 si = index(name, delimiter_, back=.true.)
214 namespace%name = name(si+1:len(name))
215 next => namespace
216 do while (si /= 0)
217 se = si
218 si = index(name(:se-1), delimiter_, back=.true.)
219 allocate(next%parent)
220 next%parent = namespace_t(name(si+1:se-1), delimiter=delimiter)
221 next => next%parent
222 end do
223
224 ! Compare namespaces
225 is_contained = namespace%contains(this)
226
227 ! Deallocate all memory
228 parent => namespace%parent
229 do while (associated(parent))
230 next => parent%parent
231 deallocate(parent)
232 parent => next
233 end do
234
235 end function namespace_is_contained_in
236
237end module namespace_oct_m
239!! Local Variables:
240!! mode: f90
241!! coding: utf-8
242!! End:
type(mpi_grp_t), public mpi_world
Definition: mpi.F90:247
integer, public mpi_err
used to store return values of mpi calls
Definition: mpi.F90:250
logical function namespace_is_contained_in(this, name, delimiter)
Definition: namespace.F90:282
elemental logical function namespace_equal(lhs, rhs)
Definition: namespace.F90:239
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:145
logical function namespace_contains(this, namespace)
Definition: namespace.F90:248
type(namespace_t), public global_namespace
Definition: namespace.F90:135
pure recursive integer function namespace_len(this)
Definition: namespace.F90:222
recursive character(len=max_namespace_len) function namespace_get(this, delimiter)
Definition: namespace.F90:199
int true(void)